async/await в .NET: от машины состояний до продакшена¶
Курс-практикум. Здесь не пересказ документации, а разбор под капотом: декомпиляция, IL, JIT-ассемблер, исходники рантайма, эксперименты с кодом и вопросы с ответами.
Платформа: .NET 10 LTS, C# 14. Новое в .NET 11 помечается .NET 11. Стенд автора: Windows 11, .NET SDK 10.0.401, рантайм 10.0.12.
Как проходить главу¶
- Прочитайте главу.
- Откройте лабораторную
start/. Там исходная точка: код с местамиPREDICT(впишите предсказание) иTODO(допишите). - Предскажите на бумаге, потом запустите:
dotnet run -c Release --project start. Расхождение между предсказанием и фактом — самое ценное, что вы получите. - Сравните с
final/, результатом главы:dotnet run -c Release --project final. Код обеих версий есть в конце каждой главы. - Если у главы есть визуализация, откройте её для сложного места.
Все команды dotnet выполняются из папки chapters (там решение, global.json и манифест инструментов). Все лабораторные собираются одной командой: dotnet build -c Release. Выводы об аллокациях и декомпиляцию делайте только в Release.
Условные обозначения¶
Факт
Результат запуска, который расходится с ожиданием или с распространённым мнением. Самые ценные места курса.
Под капотом
Разбор на уровне IL, машинного кода или исходников рантайма.
Проверить
Деталь реализации, а не контракт. Может измениться между версиями: перепроверьте на своей. В тексте выглядит так:
.NET 11
Появилось или изменилось в .NET 11. В тексте: .NET 11. Возможности, которые в .NET 10 включаются явно и не для продакшена: .NET 10 — превью
Лабораторная
Что сделать руками: предсказать, запустить, изменить.
Оглавление¶
Статус: ✅ проверено на стенде (Windows 11 или Ubuntu 26.04 — указано в главе) · 📦 перенесено из первой версии, перепроверить · 🆕 новая глава, есть только план.
| # | Глава | Лабораторная | Визуализация | Статус |
|---|---|---|---|---|
| I | Механика | |||
| 0 | Стенд и инструменты | tools/disasm.ps1 на главе 2 |
— | ✅ |
| 1 | Главная идея: async — не про потоки | потоки до и после await, 10 000 ожиданий |
схема таймера (Mermaid) | ✅ |
| 2 | Машина состояний компилятора | ручная машина состояний, сложные конструкции | карта строк C# → IL → asm | ✅ |
| 3 | Awaiter и builder | свой awaitable, builder-шпион, замер аллокаций | — | ✅ |
| 4 | Внутреннее устройство Task |
поля Task через [UnsafeAccessor], флаги, продолжения |
поле продолжений | ✅ |
| II | Контексты | |||
| 5 | Куда вернётся продолжение | четыре маршрута продолжения, ConfigureAwaitOptions, синхронные продолжения и защита стека |
маршрутизация продолжения (Mermaid), интерактивный выбор маршрута | ✅ |
| 6 | Лаборатория дедлоков | дедлок со снимком потока UI, ловушки ConfigureAwait(false), 3 способа избежать |
последовательность дедлока (Mermaid), анимация по шагам | ✅ |
| 7 | ExecutionContext и AsyncLocal |
граница async-метода, уведомления AsyncLocal, SuppressFlow и утечка, стоимость записи |
течение контекста | ✅ |
| III | Прикладной API | |||
| 8 | Исключения в async |
хранилище исключений задачи, порядок в WhenAll, async void и падение процесса, исключение против отмены |
— | ✅ |
| 9 | Отмена и таймауты | порядок и поток Register, CancelAsync, утечка связанных токенов, WaitAsync против WhenAny + Delay |
— | ✅ |
| 10 | Task API: что и когда | Run против StartNew, ContinueWith, TaskCompletionSource, WhenEach, ограничение параллелизма, SemaphoreSlim, PeriodicTimer |
— | ✅ |
| 11 | Асинхронные потоки и Channel<T> |
итераторы, AsyncLocal в итераторе, LINQ из BCL (.NET 10), режимы FullMode, завершение, AllowSynchronousContinuations |
обратное давление | ✅ |
| IV | Производительность и рантайм | |||
| 12 | ValueTask и производительность |
бенчмарк, свой IValueTaskSource, повторный await, пулинг |
— | ✅ |
| 13 | Пул потоков и «настоящая» асинхронность | голодание пула, Wait против Sleep, очереди, I/O при занятом пуле |
очереди и рост потоков | ✅ |
| 14 | Runtime Async .NET 10 — превью .NET 11 | флаг в метаданных, трасса, цена; те же замеры на .NET 10 и 11 RC1 | компилятор против рантайма | ✅ |
| 15 | Диагностика async-кода | дедлок и голодание под dotnet-stack, dumpasync, dotnet-counters, события пула изнутри |
— | ✅ |
| V | Практика | |||
| 16 | Ловушки и антипаттерны | девять блоков «найди и исправь», что ловят компилятор и анализаторы | — | ✅ |
| 17 | async в ASP.NET Core |
блокирующий и async-обработчик под нагрузкой, RequestAborted, fire-and-forget, Channel + BackgroundService, потоковые ответы |
— | ✅ |
| 18 | Задачи «что выведет код» | 12 задач, ответы проверены запуском | — | ✅ |
| 19 | Вопросы для собеседования | 40 вопросов, ответы сверены с главами | — | ✅ |
| 20 | Практикум: восемь задач | сбор данных, лимит параллелизма, таймаут, повтор, зеркала, кеш, лента, конвейер на Channel; автоматическая самопроверка |
— | ✅ |
| 21 | Память и сборка мусора в async-коде | три утечки сервиса, hoist/delay/tcs/event/channel/gen, dumpheap/gcroot/dumpasync, поколения |
— | ✅ |
| Глоссарий |