ConfigureAwait(false) to improve performance



While all await expressions capture the execution context, the decision of whether to flow synchronization context as well is controlled by the type being awaited. If you await for a Task, the synchronization context will also be captured by default. Tasks are not the only thing you can await, and I’ll describe how types can support await in the section “The await Pattern”.

Sometimes, you might want to avoid getting the synchronization context (internal another tread switch) involved. If you want to perform asynchronous work starting from a UI thread, but you have no particular need to remain on that thread, scheduling every continuation through the synchronization context is unnecessary overhead.

If the asynchronous operation is a Task or Task<T> (or the equivalent value types, ValueTask or ValueTask<T>), you can declare that you don’t want this by calling the ConfigureAwait method passing false. This returns a different representation of the asynchronous operation, and if you await that instead of the original task, it will ignore the current SynchronizationContext if there is one. 

ConfigureAwait


This code is a click handler for a button, so it initially runs on a UI thread. It retrieves the Text property from a couple of text boxes. Then it kicks off some asynchronous work—fetching the content for a URL and copying the data into a file. 
Do not use ConfigureAwait(false) when the code immediately after the await updates the UI

It does not use any UI elements after fetching those two Text properties, so it doesn’t matter if the remainder of the method runs on some separate thread. By passing false to ConfigureAwait and waiting on the value it returns, we are telling the TPL that we are happy for it to use whatever thread is convenient to notify us of completion, which in this case will most likely be a thread pool thread. This will enable the work to complete more efficiently and more quickly, because it avoids getting the UI thread involved unnecessarily after each await.

Various asynchronous APIs introduced in Windows as part of the UWP API return an IAsyncOperation<T> instead of Task<T>. This is because UWP is not .NET-specific, and it has its own runtime-independent representation for asynchronous operations that can also be used from C++ and JavaScript. This interface is conceptually similar to TPL tasks, and it supports the await pattern, meaning you can use await with these APIs. However, it does not provide ConfigureAwait. If you want to do something similar to with one of these APIs, you can use the AsTask extension method that wraps an IAsyncOperation<T> as a Task<T>, and you can call ConfigureAwait on that task instead.

If you are writing libraries, then in most cases you should call ConfigureAwait(false) anywhere you use await. This is because continuing via the synchronization context can be expensive, and in some cases it can introduce the possibility of deadlock occurring. The only exceptions are when you are doing something that positively requires the synchronization context to be preserved, or you know for certain that your library will only ever be used in application frameworks that do not set up a synchronization context. (E.g., ASP.NET Core applications do not use synchronization contexts, so it generally doesn’t matter whether or not you call ConfigureAwait(false) in those.)


ref: 

Programming C# 8.0by Ian Griffiths

https://learning.oreilly.com/library/view/programming-c-80/9781492056805/ch17.html#ch_asynchronous_language_features