Объясните, что реально происходит при async/await в C#: как компилятор трансформирует метод, как выбирается поток для продолжения, что делает ConfigureAwait(false), и почему в UI/старом ASP.NET ловят дедлок при .Result/.Wait().
Компилятор разворачивает метод в IAsyncStateMachine: локальные и позиция сохраняются в полях, await берёт awaiter (обычно TaskAwaiter) и через OnCompleted/UnsafeOnCompleted регистрирует продолжение. По умолчанию продолжение постится в текущий SynchronizationContext (если он есть), иначе — в TaskScheduler.Current (обычно пул потоков). ConfigureAwait(false) отключает захват контекста, поэтому продолжение уходит в пул и не требует возвращения в UI-контекст. Дедлок появляется, когда однопоточный контекст (WinForms/WPF или классический ASP.NET) блокируется .Result/.Wait(), а продолжение пытается вернуться в тот же контекст, который занят блокирующим ожиданием; ни то ни другое не сдвигается. Лекарство: не блокировать асинхронщину (“async all the way”), в библиотечном коде использовать ConfigureAwait(false) там, где не нужен контекст, и передавать CancellationToken.
Библиотека собеса по С#
Post #1005
2.08K
- ❤ 9