Main Issue:
Unsure of what's happening in the background, but apparently whenever the line await Task.Delay(1000); is called Unity would turn unresponsive/freezes up.
Error msg:
Tried checking callbacks from unity's profiler, but whenever the line in question were triggered unity would instantly turn unresponsive and not allowing any interaction (no callbacks/error messages were given out either).
Goal:
The goal here is to simply call tryActivities[0] then, await for 1 second and then return true, and prints "Fished successfully!", without any crashing.
Suspicions:
A suspicion I have is that the line tryActivities.Add(new Func<bool>(() => fs(currentSlot.basicData.typeID).Result)); need some sort of await? Though I'm also unsure of how to implement that either.
Inventory inventory; (Inventory.cs)
List<Func<bool>> tryActivities = new List<Func<bool>>();
public delegate Task<bool> Fish(int ID); Fish fs;
void Start()
{
fs = new Fish(activities.Fish);
tryActivities.Add(new Func<bool>(() => fs(currentSlot.basicData.typeID).Result));//await? how?
}
public void Interact()//called when a button is pressed
{
if (TryPlaceOrUse()) print("Fished successfully!");
else print("Fishing failed");
}
bool TryPlaceOrUse()
{
if (tryActivities[(int)currentSlot.basicData.myActivity]())//tryActivities[0]
return true;
return false;
}
Activities activities; (Activities.cs)
public async Task<bool> Fish(int ID)
{
await Task.Delay(1000);//crashes here
return true;
}
This might do what you want. This is how you'd use a list of async Funcs, which is really just a list of Funcs that return Tasks of bool.
public class Program
{
public delegate Task<bool> Fish(int ID);
Fish fs;
List<Func<Task<bool>>> tryActivities = new List<Func<Task<bool>>>();
public async static Task Main()
{
Console.WriteLine("Hello, World!");
Program program = new Program();
program.Start();
await program.Interact();
}
void Start()
{
fs = new Fish(Activities.Fish);
tryActivities.Add(new Func<Task<bool>>(async () => await fs(4)));//await? how? like this :)
}
public async Task Interact() //called when a button is pressed
{
if (await TryPlaceOrUse())
Console.WriteLine("Fished successfully!");
else
Console.WriteLine("Fishing failed");
}
async Task<bool> TryPlaceOrUse()
{
if (await tryActivities[0]()) //tryActivities[0]
return true;
return false;
}
}
public class Activities
{
public static async Task<bool> Fish(int ID)
{
await Task.Delay(1000);//does not crash here
return true;
}
}
Related
I've made a queue, which contains tasks to do. After creating some tasks manually with new Task() in Returns method, my whole application hangs - await current;. The body of the task is not even triggered.
ConfigureAwait(false) didn't help.
The first task in the queue, which is not created by me, but other framework is executing successfully and returning a value. Mine - doesn't. I've tried add Task.CompletedTask and then it has worked. I don't understand why I can't even reach the body of the task containing _output assignment.
IDE debugger code screenshot
---UPDATE---
The code works when I use code below. With await it doesn't. Any ideas?
current.Start();
current.Wait();
Original code
private readonly Queue<Task> _pipe;
public IPipeBuilder<TOutput> Returns(Func<IEnumerable<IExecutionResult>, TOutput> outputBuilder)
{
_pipe.Enqueue(new Task(() => // this task causes a problem and breakpoint isn't hit inside
{
_output = outputBuilder(_results);
}));
return this;
}
public async Task<TOutput> Execute()
{
Task current;
while (_pipe.TryDequeue(out current))
{
if (current.IsCommandExecution())
{
IExecutionResult result = await (Task<IExecutionResult>)current; // this awaits successfully
_results.Add(result);
}
else
{
await current; // hangs here
}
}
return await Task.FromResult(_output);
}
Usage
[HttpGet("eventflow/pipe/issue/add/{title}")]
public async Task<IActionResult> PipeAction(string title)
=> Ok(
await Pipe<IExecutionResult>()
.Validate(title)
.Handle<AddIssueCommand>(IssueId.New, title)
.Returns(results => results.First())
.Execute());
You should never use the Task constructor. This goes double on ASP.NET, since constructed tasks are always Delegate Tasks, which interfere with the ASP.NET usage of the thread pool. The actual reason that the await hangs is because manually-created tasks need to be started.
If you have synchronous work that you need to wrap into a Task to work alongside asynchronous tasks, then you should use Task.CompletedTask and Task.FromException:
private static Task SynchronousWork(Func<IEnumerable<IExecutionResult>, TOutput> outputBuilder)
{
try { _output = outputBuilder(_results); return Task.CompletedTask; }
catch (Exception ex) { return Task.FromException(ex); }
}
public IPipeBuilder<TOutput> Returns(Func<IEnumerable<IExecutionResult>, TOutput> outputBuilder)
{
_pipe.Enqueue(SynchronousWork(outputBuilder));
return this;
}
However, note that this executes outputBuilder immediately, which may not be desirable due to its side effects on _results and _output. If you want a delayed execution queue, then the type in the queue needs to be changed from Task to Func<Task>. Then you can add to it as such:
public IPipeBuilder<TOutput> Returns(Func<IEnumerable<IExecutionResult>, TOutput> outputBuilder)
{
_pipe.Enqueue(() =>
{
try { _output = outputBuilder(_results); return Task.CompletedTask; }
catch (Exception ex) { return Task.FromException(ex); }
});
return this;
}
and you would consume it by calling each delegate one at a time and inspecting the task it returns:
public async Task<TOutput> Execute()
{
while (_pipe.TryDequeue(out var currentFunc))
{
var currentTask = currentFunc();
if (currentTask.IsCommandExecution())
{
IExecutionResult result = await (Task<IExecutionResult>)currentTask;
_results.Add(result);
}
else
{
await currentTask;
}
}
return _output;
}
Okay, thank you. I've ended up with such class and Queue<Func<Task>> like you said.
public sealed class SyncTaskWrapper
{
private Func<Task> _action;
public SyncTaskWrapper(Action action)
=> _action = CreateFunc(action);
private static Func<Task> CreateFunc(Action action)
=> () =>
{
try
{
action();
return Task.CompletedTask;
}
catch (Exception exception)
{
return Task.FromException(exception);
}
};
public static implicit operator Func<Task>(SyncTaskWrapper #this)
=> #this._action;
}
with usage
_pipe.Enqueue(new SyncTaskWrapper(() =>
_output = outputBuilder(_results)));
I try to wait for the class to be finished with instantiate.
My architecture is the following. Cook is inheriade from CookChief.
And if I instantiate cook, CookChief is creating himself, but CookChief is calling 1 other class named Cookhelper the cookhelper is waiting for a input and for this input method i want to wait in Cook.
The thing is iam creating this in MVVM Galasoft and my entry point is the CookViewmodel, with a relaycommand.
In the code below you can see my architecture. To say it short I want to wait until this bool processed = await Task.Run(() => ValidateForDeviceId()); is finished.
My first step was to outsource the constructer of each class. And create a init method.
This is my code:
public CookViewModel()
{
startCookButtonCommand = new RelayCommand(Cook);
}
private async Task Cook()
{
cook.Init();
}
public class Cook : CookChief
{
public Cook()
{
}
public async Task Init()
{
await this.CookChiefInit();
//here I want to wait until CookChiefInit is finished
Cooking();
}
public void Cooking()
{
MessageBox.Show("Input received");
}
}
Now the Cookchief:
public Cookchief()
{
}
protected async Task CookchiefInit()
{
this.Cookhelper = new Cookhelper();
Cookhelper.CookHelperInit();
}
And in the CookHelper we do this:
public CookHelper()
{
}
public void CookHelperInit()
{
this.driverWindow = new DriverWindow();
startProc();
}
private async void startProc()
{
ShowOrCloseDriverWindow(true);
//this is the task what we wait for before we can repeat
bool processed = await Task.Run(() => ValidateForDeviceId());
if(processed)
{
ShowOrCloseDriverWindow(false);
}
else
{
MessageBox.Show("DriverError");
}
}
private bool ValidateForDeviceId()
{
for (; ; )
{
this.deviceId = Input.deviceId;
if (deviceId > 0)
{
break;
}
}
return true;
}
Per the discussion in the comments, the problem here was that the initialization routine mixed synchronous and asynchronous methods and calls. Additionally, some async methods were called without the await keyword. The solution was to make all calls asynchronous and await them.
cook.Init() needs an await:
private async Task Cook()
{
await cook.Init();
}
In CookchiefInit(), the CookHelperInit() call needs to be awaited:
protected async Task CookchiefInit()
{
this.Cookhelper = new Cookhelper();
Cookhelper.CookHelperInit();
}
In order to await CookHelperInit(), it needs to be made asynchronous. The startProc() call is to an async method, so it must also be awaited:
public async Task CookHelperInit()
{
this.driverWindow = new DriverWindow();
await startProc();
}
I have the following method in my application
public async void Method()
{
bool updated = false;
foreach (Feed feed in Feeds)
{
if (await feed.Update())
{
updated = true; // At least one feed was updated
}
}
if (updated)
{
// Do Something
}
}
As you can see, the method Update() is called one by one, on each item in the list. I would instead like to call it on all the items simultaneously, and know whether one of them succeeded.
The method Update() is found in the class Feed
public async Task<bool> Update()
{
try
{
WebRequest wr = WebRequest.Create(URL);
wr.Timeout = 5000;
using (WebResponse response = await wr.GetResponseAsync())
{
XmlDocument feed = new XmlDocument();
feed.Load(response.GetResponseStream());
// Do Something
return true;
}
}
catch (WebException we)
{
return false;
}
}
EDIT:
So far I've been trying to solve this problem using async methods with and without return values.
public async void Update()
{
if (await UpdateFeeds())
{
// Do something
}
}
public async Task<bool> UpdateAllFeeds()
{
// Update all the feeds and return bool
}
Then I realized I would still have the same problem within UpdateAllFeed(). They could run simultaneously if I changed Update() in Feed to an async void method, but then I would have no callback.
I don't know how to run multiple asynchronous methods and only callback when they're all done.
Create a list of Task<bool> and then use Task.WhenAll
List<Task<bool>> tasks = new List<Task<bool>>();
foreach (var feed in feeds)
{
tasks.Add(feed.Update());
}
await Task.WhenAll(tasks);
var updated = (from t in tasks where t.Result select t).Any();
public async void Method()
{
bool updated = false;
Parallel.ForEach(Feeds, feed =>
{
if (feed.Update())
updated = true; // At least one feed was updated
});
if (updated)
{
// Do Something
}
}
I have a form, like below, that accepts a Task<T>, waits for completion and then returns after await by closing the form:
public partial class SomeForm<T> : Form
{
public T ReturnValue { get; private set; }
private Task<T> Task { get; set; }
public SomeForm(string waitingText, Task<T> task)
{
InitializeComponent();
...
PerformTask();
}
private async void PerformTask()
{
ReturnValue = await Task;
this.Close();
}
}
However, whilst this method runs happily, it gets to ReturnValue = await Task; and then does not go any further. The method will run normally without being sent to the method and does not delay. I have a feeling it's to do with how I'm using async and await, but I'm new to TPL etc.
Please help me identify what's wrong with the above script, and in identifying why it never returns.
Edit: TaskA was a typo. Here's the Task's method; ImportedFunctions. BS_Robots_LoadDrive(..) is a DllImport of a C++ function, which works just fine synchronously, even on another thread (like in the final snippet), but not with an async paramter.
public uint LoadDisc()
{
uint response = ImportedFunctions.BS_Robots_LoadDrive(DriveLetters[0],
(int)BSRobotConstants.BIN_ID_DEFAULT,
(int)BSRobotConstants.POSITION_TYPE_INPUTBIN,
0);
switch (response)
{
case BSRobotConstants.OK:
case BSRobotConstants.OK_WITH_MESSAGE:
case BSRobotConstants.FROMTRAY_NO_DISC:
case BSRobotConstants.INVALID_DRIVE:
case BSRobotConstants.INVALID_POSITION:
case BSRobotConstants.TOTRAY_NO_DISC:
case BSRobotConstants.TOTRAY_NOT_OPEN:
case BSRobotConstants.FATAL_ERROR:
break;
case BSRobotConstants.BUSY:
break;
case BSRobotConstants.TOTRAY_HAS_DISC:
RejectDisc();
response = LoadDisc();
break;
}
return response;
}
This works:
private async void PerformTask()
{
Task.Start();
Task.Wait();
ReturnValue = Task.Result;
DialogResult = DialogResult.OK;
}
But the first code snippet doesn't.
The task does not continue past ReturnValue = await TaskA; because it is not returning. Verify the Task is running and not getting stuck.
To property utility async-await for object construction use an async factory method.
See: How to initialize an object using async-await pattern
public class Form1<T> : Form
{
public Form1(string waitingText, Task<T> task)
{
Task = Execute(task);
Controls.Add(new Label { Text = waitingText });
}
public T ReturnValue { get { return Task.Result; } }
public Task<T> Task { get; private set; }
private async Task<T> Execute(Task<T> task)
{
var result = await task;
Close();
return result;
}
}
Usage:
var form = new Form1<int>("Hello", Task.Delay(1000).ContinueWith(_ => 1));
form.Show();
var returnValue = await form.Task;
Console.WriteLine(returnValue);
My question is, what does the deferral.complete() method exactly, does this method call the event task.Compledet, or is there a way to call a method from the BackgroundTaskSyncer in my class BackgroundSyncer ????
When i run the Programm i will do the Run method from BackgroundTaskSyncer but nothing in the other class??
namespace NotificationTask
{
public sealed class BackgroundTaskSyncer : IBackgroundTask
{
public void Run(IBackgroundTaskInstance taskInstance)
{
BackgroundTaskDeferral deferral = taskInstance.GetDeferral();
deferral.Complete();
}
}
}
namespace Services
{
public static class BackgroundSync
{
private static async Task RegisterBackgroundTask()
{
try
{
BackgroundAccessStatus status = await BackgroundExecutionManager.RequestAccessAsync();
if (status == BackgroundAccessStatus.AllowedWithAlwaysOnRealTimeConnectivity || status == BackgroundAccessStatus.AllowedMayUseActiveRealTimeConnectivity)
{
bool isRegistered = BackgroundTaskRegistration.AllTasks.Any(x => x.Value.Name == "Notification task");
if (!isRegistered)
{
BackgroundTaskBuilder builder = new BackgroundTaskBuilder
{
Name = "Notification task",
TaskEntryPoint =
"NotificationTask.BackgroundTaskSyncer"
};
builder.SetTrigger(new TimeTrigger(15, false));
builder.AddCondition(new SystemCondition(SystemConditionType.InternetAvailable));
BackgroundTaskRegistration task = builder.Register();
task.Completed += new BackgroundTaskCompletedEventHandler(OnCompleted);
task.Progress += new BackgroundTaskProgressEventHandler(OnProgress);
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("The access has already been granted");
}
}
private static void OnCompleted(IBackgroundTaskRegistration task, BackgroundTaskCompletedEventArgs args)
{
ToTheBackGroundWork();
}
Deferrals were created to work around a problem with async void events and methods. For example, if you had to await during a background operation, you would use an async void Run method. But the problem with that is that the runtime has no idea that you actually have more work you want to do.
So, a deferral is an object that you can use to inform the runtime "I'm really done now." A deferral is only necessary if you need to await.
I have a blog post that goes into "asynchronous event handlers" and deferrals in more detail.