简体   繁体   中英

How to use ConfigureAwait on async methods

I am looking into correct uses of ConfigureAwait I have identified a valid use case for ConfigureAwait (ie after the await does not require the calling thread synchronisationcontext) and couldn't see any advice on using ConfigureAwait on async methods

My code looks like the following

Public async Task StartMyProgram()
{
     await RunBackgroundTask();
}

Private async Task RunBackgroundTask()
{
     await Task.Delay(5000);
}

To use ConfigureAwait correctly am I assuming that this should be used on both await calls like the below code:

Public async Task StartMyProgram()
{
     await RunBackgroundTask().ConfigureAwait(false);
}

Private async Task RunBackgroundTask()
{
     await Task.Delay(5000).ConfigureAwait(false);
}

or do I just need it on the private RunBackgroundTask method?

This is a simplification, but you can assume that ConfigureAwait(false) is a subtle way to say "hey, the stuff you are about to call will not grab the current synchronization context".

The keyword here is current : the synchronization context is used to, well, synchronize with the asynchronous state machine. Your asynchronous methods are turned into tasks, and the whole sequence must returnn only when all complete as you requested. To perform such synchronization, the inner task scheduler requires a synchronization context. When you are writing a library, you have no idea what is the caller doing, and particularly, you are now aware of additional threads that may be running asynchronous methods (eg concurrent asynchronous methods in different threads, or message pumps). For this reason, you play safe calling ConfigureAwait(false) , indicating to the runtime not to borrow (and capture) the caller synchronization context, but use a new one.

Why would you do that? First, because borrowing something in a non deterministic state is not nice. But more important, to avoid deadlocks: in fact, during the execution of your asynchronous method, you are using by default the captured context of the caller. This means that you might end up in deadlocks and/or subtle issues because the thread which is required to run task can be stuck by your method, thus ending up in deadlock.

By default, when you use async/await, it will resume on the original thread that started the request. However, if another long-running process currently has taken over that thread, you will be stuck waiting for it to complete. To avoid this issue, you can use a method called ConfigureAwait with a false parameter. When you do, this tells the Task that it can resume itself on any thread that is available instead of waiting for the thread that originally created it. This will speed up responses and avoid many deadlocks.

With ConfigureAwait(true) (the default one), when you resume on another thread, the thread synchronization context is lost thus losing culture and/or language settings along with other things like HttpContext.Current (this happens in .NET Standard).

As a rule of thumb, you should always use ConfigureAwait(false) in library codes, and also in your code when you are multi-thread. This is an example as the default behaviour may not be suitable for most of the cases.

or do I just need it on the private RunBackgroundTask method?

Each method should make its ConfigureAwait(false) decision on its own. This is because each method captures its own context at await , regardless of what its caller/called methods do. ConfigureAwait configures a single await ; it doesn't "flow" at all.

So, RunBackgroundTask needs to determine "do I need to resume on my context?" If no, then it should use ConfigureAwait(false) .

And StartMyProgram needs to determine "do I need to resume on my context?" If no, then it should use ConfigureAwait(false) .

When entering RunBackgroundTask , you have no clue of what the SynchronizationContext is. So you really don't need to capture it and should keep using .ConfigureAwait(false) .

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