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)?
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.
ASP.NET generally does not allow fire-and-forget (async void) operations to be kicked off from within a request. See https://stackoverflow.com/a/22484832/59641 for a further explanation of this behavior and some potential workarounds.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.