When should I use ConfigureAwait(true)?
问题
Has anyone come across a scenario for using ConfigureAwait(true)
? Since true
is the default option I cannot see when would you ever use it.
回答1
true to attempt to marshal the continuation back to the original context captured; otherwise, false.
It's actually more like saying that ConfigureAwait(true)
is like using .ContinueWith( t => {...}, TaskScheduler.FromCurrentSynchronizationContext())
,
where ConfigureAwait(false)
is like using .ContinueWith( t => {...})
.
If you pass false, then the continuation is being allowed to run on a thread-pool thread instead of pulling back to the current synchronization context.
回答2
One possibility I can see is if you're writing code in a library and you want to allow your callers to decide whether it's appropriate to continue on the original context1 (although I'd usually argue for never continuing on the original context from within library code)
Your caller will either pass a bool
parameter or set some configuration value, and so you will not know until runtime what the correct argument value is.
This is the general type of answer for APIs such as this that have a no-args variant and a variant with a single argument, where the no-args variant is documented as "the same as the single argument variant with well-known value x" - if you won't know until runtime what the correct value to pass is, then you should just call the single argument variant with the correct runtime value.
1 E.g. your caller is also supplying a delegate. Your caller will know (and can decide) whether that delegate needs to be back on the original context or not.
回答3
Since true is the default option I cannot see when would you ever use it.
One obvious use case is when you want to make sure that every time something is awaited, there is made an explicit and deliberate choise about what to do with the synchronization context.
Example policy from http://newmedialabs.co.za/blog/post/SynchronizationContexts:
At NML we prefer to always state explicitly how we want the task continuation to occur. So even though a Task's default is ConfigureAwait(true), we still specify it as such so that we are always cognizant of what's happening "under the hood".
Although to improve readability they use an extension instead of ConfigureAwait(true)
directly:
However, when you look at a lot of code, some with ConfigureAwait(true) and some with ConfigureAwait(false), it's not easy to spot where they differ. So we use either ConfigureAwait(false), or a useful extension method, ContinueOnCapturedContext(). It does the same thing, but just differentiates it from ConfigureAwait(false) in a more visual manner.
回答4
If you are using Azure's Durable Functions, then you must use ConfigureAwait(true)
when awaiting your Activity functions:
string capture = await context.CallActivityAsync<string>("GetCapture", captureId).ConfigureAwait(true);
Otherwise you will likely get the error:
"Multithreaded execution was detected. This can happen if the orchestrator function code awaits on a task that was not created by a DurableOrchestrationContext method. More details can be found in this article https://docs.microsoft.com/en-us/azure/azure-functions/durable-functions-checkpointing-and-replay#orchestrator-code-constraints.".
Further information can be found here.
Which do I use, ConfigureAwait True or False?
In this video we answer the ever popular question “Which do I use, ConfigureAwait True or False?”.
The direct answer to this question is:
– If you are a writing code for the UI, use ConfigureAwait(true).
– If you are writing code in a library that will be shared, use ConfigureAwait(false)
If you want to know why, then keep watching until the end, because I teach you the difference between ConfigureAwait(true) and ConfigureAwait(false).
We start by understanding exactly how the await keyword in C# works. You learn about the continuation task and how to properly use ConfigureAwait to control which thread the continuation task runs on and why that’s important.
We talk about why the UI code relies on ConfigureAwait(true) and what happens if you set ConfigureAwait(false). Hint: you’ll get a threading exception.
We’ll also cover why you need to use ConfigureAwait(false) in all of your library code to help protect the consumers of your code from encountering deadlocks and other threading issues.