简体   繁体   中英

fire and forget an async Task method sometimes not invoke

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:

  1. How to make the call to DoSomethingAsync() without await will always run and complete? (I don't care the case AppDomain restart/crash)

  2. 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:

  1. You have a deadlock somewhere in one of your methods, preventing it from completing and blocking the await from resuming.
  2. All of your thread pool threads are blocking for some reason, preventing pending Tasks from running.
  3. You're running the async method in a synchronization context and something is holding up the context, preventing it from running the dispatched callbacks. Typically the context would be the UI thread and generally this is pretty obvious, since it locks up your application UI.

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM