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).
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).
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.
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.
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!
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).
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