When using await
, by default the SynchronizationContext
(if one exists) is captured and the codeblocks after the await
(continuation blocks) is executed using that context (which results in thread context switches).
public async Task DoSomethingAsync()
{
// We are on a thread that has a SynchronizationContext here.
await DoSomethingElseAsync();
// We are back on the same thread as before here
//(well sometimes, depending on how the captured SynchronizationContext is implemented)
}
While this default might make sense in the context of the UI where you want to be back on the UI-thread after an asynchronous operation completes, it doesn't seem make sense as the default for most other scenarios. It certainly doesn't make sense for internal library code, because
- It comes with the overhead of unnecessary thread context switches.
- It is very easy to accidentaly produce deadlocks (as documented here or here).
It seems to me that Microsoft have decided for the wrong default.
Now my question:
Is there any other (preferably better) way to solve this than by cluttering all await
calls in my code with .ConfigureAwait(false)
? This is just so easy to forget and makes the code less readable.
Update:
Would it maybe suffice to call await Task.Yield().ConfigureAwait(false);
at the beginning of each method? If this would guarantee me that I will be on a thread without a SynchronizationContext
aferwards, all subsequent await
calls would not capture any context.