I have an async method:
public async Task DoSomethingAsync(){
...
await ...
await ...
....
return await SaveAsync();
}
In most time, I call this method by:
await DoSomethingAsync()
This call works as expected. But somewhere, I need to call this method as fire and forget:
public void OtherMethod()
{
...
DoSomethingAsync(); //fire and forget here
}
In this case, sometimes the Task DoSomethingAsync()
runs and completes, but sometimes the task never invoked (or invoke some await
s within DoSomethingAsync()
but never complete the last await SaveAsync();
).
I'm trying to make sure the task will be invoked in fire and forget manner by these code:
public void OtherMethod()
{
...
Task.Factory.StartNew(() =>
{
await DoSomethingAsync();
}); //fire and forget again here
}
However, this does not work as expectation. So my questions are:
How to make the call to DoSomethingAsync()
without await
will always run and complete? (I don't care the case AppDomain restart/crash)
If I remove all async/await
code within DoSomethingAsync()
and replace await
by .ContinueWith()
, then the call to Task DoSomethingAsync()
(not have async
in method declaration) will be invoked and sure to complete (ignore case AppDomain restart/crash), if yes, how long from the call (I don't think that I'll be happy if the Task will be invoked after 10 minutes)?
The call to the async method starts an asynchronous task. However, because no Await operator is applied, the program continues without waiting for the task to complete.
Async void methods can wreak havoc if the caller isn't expecting them to be async. When the return type is Task, the caller knows it's dealing with a future operation; when the return type is void, the caller might assume the method is complete by the time it returns. This problem can crop up in many unexpected ways.
For methods other than event handlers that don't return a value, you should return a Task instead, because an async method that returns void can't be awaited. Any caller of such a method must continue to completion without waiting for the called async method to finish.
Async code can be used for both I/O-bound and CPU-bound code, but differently for each scenario. Async code uses Task<T> and Task , which are constructs used to model work being done in the background. The async keyword turns a method into an async method, which allows you to use the await keyword in its body.
You're probably getting an exception somewhere in DoSomethingAsync
, which you cannot observe because you're ignoring the task. This is exactly the behavior you're asking for, since you're telling the code to "forget" the task.
To observe the exception, you cannot "forget" the task:
public Task OtherMethodAsync()
{
...
return DoSomethingAsync();
}
And at some point, await
(or Wait
) the returned task. That is how you know the task will run and complete.
The awaits should be working fine, so there is likely something else going on here that is holding up one or more of your methods being awaited. There are a few possibilities:
If you can attach with the VS debugger and observe what's happening, try pausing and looking at the Parallel Stacks view. This should help narrow down which possibilities to consider.
As Stephen pointed out, it's also possible that an Exception is occurring when you're calling it fire-and-forget. If you're not already, make sure you handle TaskScheduler.UnobservedTaskException to log any events like this. Note that this is called from the finalizer, so the time at which it gets called is non-deterministic. This can make debugging tricky, since the event might not fire until much later than the actual event that caused the exception. As such, I recommend following Stephen's advice and saving the Task to await or Wait somewhere else later.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With