C#: Understanding ConfigureAwait(false)

shuheieda9 462 views 27 slides Feb 01, 2020
Slide 1
Slide 1 of 27
Slide 1
1
Slide 2
2
Slide 3
3
Slide 4
4
Slide 5
5
Slide 6
6
Slide 7
7
Slide 8
8
Slide 9
9
Slide 10
10
Slide 11
11
Slide 12
12
Slide 13
13
Slide 14
14
Slide 15
15
Slide 16
16
Slide 17
17
Slide 18
18
Slide 19
19
Slide 20
20
Slide 21
21
Slide 22
22
Slide 23
23
Slide 24
24
Slide 25
25
Slide 26
26
Slide 27
27

About This Presentation

This slides explains why ConfigureAwait(false) needs to be called when we use async await. This slides is based on the following blog by Microsoft.
https://devblogs.microsoft.com/dotnet/configureawait-faq/


Slide Content

Understanding ConfigureAwait (false) Shuhei Eda

If you’ve already read this blog , Finish reading this slides. Do not waste your time!

Agenda Understanding SynchronizationContext and TaskScheduler How do SynchronizationContext and TaskScheduler relate to await? Problems of Posting callbacks What does ConfigureAwait (false) do?

Understanding SynchronizationContext and TaskScheduler

Official definition of SynchronizationContext Official document says… “Provides the basic functionality for propagating a synchronization context in various synchronization models.” Too abstract!!!

Easier explanation of SynchronizationContext Provides Post method which passes a delegate(callback, action..) from one thread to another Base method just enqueues a callback into ThreadPool Current Thread ThreadPool Thread Post

Sample code of SynchronizationContext Output ThreadId : 1 Action Called ThreadId : 11

Derived-Type of SynchronizationContext Some frameworks have a specific thread E.X. Winforms sets Derived-Type of SynchronizationContext to allow the context to be brought onto the UI thread. The callback is invoked on UI thread Current Thread UI Thread Post ( BeginInvoke )

Sample code of SynchronizationContext Output ThreadId : 1 Action Called ThreadId : 1

TaskScheduler Very Roughly Speaking: Task’s version of SynchronizationContext Provides “ QueueTask ” method which enqueues tasks to the Thread pool. If the LongRunning option is true, it creates a new thread.

How do SynchronizationContext and TaskScheduler relate to await?

Write asynchronous code (Before .NET 4.0) Use TaskScheduler Use SynchronizationContext Thread 1 Thread 2 ContinueWith GetStringAsync Post back

Write asynchronous code (Before .NET 4.0) Use TaskScheduler Use SynchronizationContext Thread 1 Thread 2 ContinueWith GetStringAsync SynchronizationContext is captured! Post back

Write asynchronous code (After .NET 4.5) Can use async await keyword ContinueWith GetStringAsync Post back Thread 1 Thread 2

Detailed capturing behavior

Problems of Posting callbacks

Problems of Posting callbacks Deadlock If an original thread calls Wait(), Result, or GetResult (), it gets blocked until the thread running the task finishes. The subsequent thread waits until the original thread becomes available. Performance Enqueueing the callback to another thread is an expensive operation Cannot do post back Thread 1 Thread 2 Blocking HeavyAsync () .Result Doing heavy tasks Deadlock!

Problems of Posting callbacks Deadlock If an original thread calls Wait(), Result, or GetResult (), it gets blocked until the thread running the task finishes. The subsequent thread waits until the original thread becomes available. Performance Enqueueing the callback to another thread is an expensive operation Cannot do post back Thread 1 Thread 2 Blocking HeavyAsync () .Result Doing heavy tasks I will restart after Thread 2’s method is done. Deadlock!

Problems of Posting callbacks Deadlock If an original thread calls Wait(), Result, or GetResult (), it gets blocked until the thread running the task finishes. The subsequent thread waits until the original thread becomes available. Performance Enqueueing the callback to another thread is an expensive operation Cannot do post back Thread 1 Thread 2 Blocking HeavyAsync () .Result Doing heavy tasks I will restart after Thread 2’s method is done. I will do post-back when Thread1 becomes available Deadlock!

Sample code of deadlock Result: 1 : Main Start 1 : ChildSampleAsync Start This block is trying to be executed in Thread1, but Thread 1 is blocked, so the deadlock occurs. Since the “Result” method is called, Thread1 gets blocked

What does ConfigureAwait (false) do?

ConfigureAwait (false) = Prevents capturing SynchronizationContext Sample code of capturing process ConfigureAwait (false) bypasses the following block of code.

If ConfigureAwait (false) is called.. It will not post the callback. The code block after the “await” keyword will continue running on the same thread.  Thread 1 Thread 2 Blocking HeavyAsync () .Result Doing heavy tasks No post happens and the method is processed in the same thread.

Sample code of NON-deadlock Result: 1 : Main Start 1 : ChildSampleAsync Start 7 : ChildSampleAsync End 1 : Main End This code block runs on another thread, not in original thread. ConfiureAwait (false) is called.

Advantages of calling ConfigureAwait (false) Avoiding deadlocks Performance Since no queueing of the callback  occurs.

Guidance of using ConfigureAwait (false)   Should use ConfigureAwait (false) general-purpose libraries ASP.NET Core Console App Should NOT use ConfigureAwait (false) Win Forms ASP.NET ( HttpContext.Current might be badly affected ) WPF Silverlight

Reference https://devblogs.microsoft.com/dotnet/configureawait-faq/