Why ConfigureAwait(false) is not the default option?

C#Async Await

C# Problem Overview


As you know, it it a good idea to call Task.ConfigureAwait(false) when you are waiting on a task in a code that does not need to capture a synchronization context, because it can cause deadlocks otherwise.

Well, how often do you need to capture a synchronization context? I my practice, very rarely. In most situations I am working with "library" code that pretty much forces me to use Task.ConfigureAwait(false) all the time.

So my question is pretty simple: why Task.ConfigureAwait(false) is not the default option for a task? Would not it be much better to force "high-level" code to use Task.ConfigureAwait(true)? Is there a historical reason for it, or am I missing something?

C# Solutions


Solution 1 - C#

Most code that works with .ConfigureAwait(false) also works, although subobtimal, with .ConfigureAwait(true). Yes, not all code, but still most. The current default lets the highest percentage of code work without tinkering with settings that an average programmer might not understand.

A different default would just lead to thousands of questions about why the code does not work, and worse yet, thousands of answers in the form of "Microsoft sucks, they make you write Control.CheckForIllegalCrossThreadCalls = false; in every program. Why isn't that the default?" rather than actually adding the appropriate .ConfigureAwait(true) calls.

Solution 2 - C#

Look at the second example solution from that link:

public async void Button1_Click(...)
{
  var json = await GetJsonAsync(...);
  textBox1.Text = json;
}

public class MyController : ApiController
{
  public async Task<string> Get()
  {
    var json = await GetJsonAsync(...);
    return json.ToString();
  }
}

If the default behaviour was ConfigureAwait(false), the textBox1.Text = json; statement would execute on a random thread pool thread instead of the UI thread.

Both snippets look like code someone could reasonably write, and by default one of them has to be broken. Since deadlocks are a lot less dangerous and easier to detect than thread-unsafe accesses, picking ConfigureAwait(true) as the default is the more conservative choice.

Solution 3 - C#

Just because your typical use case requires ConfigureAwait(false), it doesn't mean that it is the "correct" or most used option.

One of the things async/await is designed for, is to write responsive GUI programs. In such cases, returning to the UI thread after offloading some work to a Task is critical, since UI updates can only happen from the main thread on most Windows GUI platforms. Async/await helps GUI developers do the right thing.

This is not the only example where the default option makes better sense. I can only speculate, but I would suspect that the decision for the ConfigureAwait default is based on making sure async works with as little friction as possible, for the use cases that Microsoft anticipates it will be used for the most. Not everyone writes frameworks.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRX_DID_RXView Question on Stackoverflow
Solution 1 - C#user743382View Answer on Stackoverflow
Solution 2 - C#Tavian BarnesView Answer on Stackoverflow
Solution 3 - C#driisView Answer on Stackoverflow