According to best practices it is recommended to use .ConfigureAwait(false)
with async/await
keywords if you can:
await Task.Run(RunSomethingAsync).ConfigureAwait(false);
Can you please give me an example of a situation when I cannot use .ConfigureAwait(false)
?
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.
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!
To improve performance and avoid potential deadlocks, use ConfigureAwait(false) in any non-UI code. The exception here is app-level code, such as Windows Forms, WPF, and ASP.NET. ConfigureAwait(true) corresponds to the default behavior and does nothing meaningful, therefore such calls can be safely omitted.
You "cannot" use ConfigureAwait(false)
when you actually care about the synchronization context you're in. For example, imagine the following in a GUI application:
public async void SomeButtonClick(object sender, EventArgs e)
{
var result = await SomeAsyncOperation().ConfigureAwait(false);
textBox.Text = result;
}
When you return from ConfigureAwait
, you wont be back on the UI thread. This will cause an InvalidOperationException
.
From the source: Asynchronous .NET Client Libraries for Your HTTP API and Awareness of async/await's Bad Effects:
When you are awaiting on a method with await keyword, compiler generates bunch of code in behalf of you. One of the purposes of this action is to handle synchronization with the UI (or main) thread. The key component of this feature is the
SynchronizationContext.Current
which gets the synchronization context for the current thread.SynchronizationContext.Current
is populated depending on the environment you are in. TheGetAwaiter
method of Task looks up forSynchronizationContext.Current
. If current synchronization context is not null, the continuation that gets passed to that awaiter will get posted back to that synchronization context.When consuming a method, which uses the new asynchronous language features, in a blocking fashion, you will end up with a deadlock if you have an available SynchronizationContext. When you are consuming such methods in a blocking fashion (waiting on the Task with Wait method or taking the result directly from the Result property of the Task), you will block the main thread at the same time. When eventually the Task completes inside that method in the threadpool, it is going to invoke the continuation to post back to the main thread because
SynchronizationContext.Current
is available and captured. But there is a problem here: the UI thread is blocked and you have a deadlock!
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