Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Async library best practice: ConfigureAwait(false) vs. setting the synchronization context

It's well-known that in a general-purpose library, ConfigureAwait(false) should be used on every await call to avoid continuing on the current SynchronizationContext.

As an alternative to peppering the entire codebase with ConfigureAwait(false), one could simply set the SynchronizationContext to null once, at the public surface method, and restore it before returning to the user. In other words:

public async Task SomeSurfaceMethod()
{
    var callerSyncCtx = SynchronizationContext.Current;
    SynchronizationContext.SetSynchronizationContext(null);
    try
    {
        // Do work
    }
    finally
    {
        SynchronizationContext.SetSynchronizationContext(callerSyncCtx);
    }
}

This could also be wrapped in a using for better readability.

Is there a disadvantage to this approach, does it not end up producing the same effect?

The major advantage is obviously readability - the removal of all ConfigureAwait(false) calls. It may also reduce the likelihood of forgetting a ConfigureAwait(false) somewhere (although analyzers mitigate this, and it could be argued that developers could just as well forget changing the SynchronizationContext).

A somewhat exotic advantage is not embedding the choice of capturing the SynchronizationContext or not in all methods. In other words, in one case I may want to run method X with a SynchronizationContext, while in another I may want to run the same method without one. When ConfigureAwait(false) is embedded everywhere that isn't possible. Granted, this is quite a rare requirement, but I bumped into it while working on Npgsql (triggering this question).

like image 656
Shay Rojansky Avatar asked Sep 12 '16 09:09

Shay Rojansky


People also ask

Which do I use ConfigureAwait True or false?

In 99% of the cases, you should use ConfigureAwait(false). In . NET Framework by default the Task execution will continue on the captured context, this is ConfigureAwait(true).

Should I always use ConfigureAwait false?

As a general rule, every piece of code that is not in a view model and/or that does not need to go back on the main thread should use ConfigureAwait false. This is simple, easy and can improve the performance of an application by freeing the UI thread for a little longer.

When would you not use ConfigureAwait false?

If the await task. ConfigureAwait(false) involves a task that's already completed by the time it's awaited (which is actually incredibly common), then the ConfigureAwait(false) will be meaningless, as the thread continues to execute code in the method after this and still in the same context that was there previously.

What is ConfigureAwait () used for?

ConfigureAwait in ActionIt is what happens when you await a task. You capture the current context before awaiting the task, leaving it to the task context, then recovering (re-entering) it back when the task completes. This process is highly expensive and in many scenarios, you do not need it!


1 Answers

As @MrinalKamboj wrote in the comments, the approach of temporarily setting the SynchronizationContext to null at the public surface method and setting back has already been proposed here. There doesn't seem to be any specific problem associated with this (see Stephen Cleary's answer here).

like image 191
Shay Rojansky Avatar answered Oct 06 '22 01:10

Shay Rojansky