Why ConfigureAwait(false) is not the default option? [closed]
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?
Solution 1:
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:
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.