Async in C# The good, the bad and the ugly πŸ˜‹πŸ˜’πŸ˜­

Hi, I’m Stu ◍ ◍ ◍ ◍ F# |> I ❀ 8 years of experience in .NET Organiser of Bristol F# meetup and DDD South West Passionate about Open Source You can find me at @stuartblang

Why an Async talk?

History of Async You are here! 2011 2018 Async/Await introduced .NET 4.5 C# 5

β€œ It really troubles me how much async, bad async, really bad async we see in the wild Kathleen Dollard - .NET Rocks! #1143

Async is an abstraction Safe Abstractions Dangerous Abstractions Async/Await β€œPowerful” Leaky Magic

The Good ◍ Non-blocking waiting ◍ There is no thread!

The Bad ◍ ◍ ◍ ◍ ◍ ◍ Not clear what is true async Minor performance overhead Duplicated code Async can’t go everywhere Risk of async deadlocks Doing it wrong is much worse that not doing it at all

How does it work? Compiler generated code

How does it work?

How does it work? True async Task.FromResult(…) Task.Run(() => …)

.ConfigureAwait(false) What’s that about?

Synchronization Context What’s that about?

How does it work?

Continuing on Captured Context

Synchronization Context Cont.

Synchronization Context Cont. WindowsFormsSynchronizationContext DispatcherSynchronizationContext Default (ThreadPool) SynchronizationContext AspNetSynchronizationContext

SynchronizationContext Behaviors Specific Thread Used to Execute Delegates Exclusive (Delegates Execute One at a Time) Ordered (Delegates Execute in Queue Order) Send May Invoke Delegate Directly Post May Invoke Delegate Directly WinForms Yes Yes Yes If called from UI thread Never WPF Yes Yes Yes If called from UI thread Never Default No No No Always Never ASP.NET No Yes No Always Always

Deadlock

KA-BLAMO!

KA-BLAMO!

ContextFreeTask

vs-threading

Formal definition of async deadlocks You are susceptible to deadlocks if: 1. 2. You have a current SynchronizationContext that enforces exclusive access; Some code further into your call stack has access to it and can/does: a. Synchronously block on some async code; b. Within that async code awaits an incomplete task that does not use .ConfigureAwait(false), or temporarily removes the context. If you use .Result, .Wait(), .GetAwaiter().GetResult() you have done a dangerous thing, and you should be prepared to guard against naughty awaiters (you may not even control).

Resources Prevention Methods ◍ ◍ ◍ ◍ ◍ ◍ ◍ ◍ .ConfigureAwait(false) all the things ContextFreeTask Comment the code null the SynchronizationContext (with handy helper functions) async top to bottom (replace our libraries and framework where we have to) Deadlock detection in QA & Prod Detect deadlocks in unit tests? Use ASP.NET Core! Automated Tools ◍ ◍ ◍ ◍ ◍ Microsoft’s AsyncPackage (Roslyn Analyzer) Async006 - Detects more blocking calls than you can shake a stick at. ConfigureAwait.Fody ConfigureAwait Checker for ReSharper ConfigureAwaitChecker - Roslyn Analyzer + VSIX DeadlockDetection

Awesome async resources ◍ Stephen Cleary β—Œ https://blog.stephencleary.com/ ◍ Anthony Steele β—Œ Avoiding basic mistakes in async await β—Œ Resynchronising async code

Async Guidance ◍ davidfowl/AspNetCoreDiagnosticScenarios - AsyncGuidance.md

οΏ½οΏ½ Thanks! Any questions? You can find me at @stuartblang & stuart.b.lang@gmail.com

οΏ½οΏ½ Thanks! Any questions? You can find me at @stuartblang & stuart.b.lang@gmail.com