Как работает await с методом без async
Что проверяют
Понимаете ли вы, что await работает с возвращаемым объектом, а не с методом, и что async это деталь реализации, а не часть контракта. Следом обычно спрашивают, когда можно убрать async/await и просто вернуть Task, и чем это грозит.
Как отвечать
Разведите два случая.
Первый: ждём метод без async. Это законно, если метод возвращает ожидаемый тип: Task, Task<T>, ValueTask. Например, Task<string> LoadAsync() => _http.GetStringAsync(url); не помечен async, но await LoadAsync() работает. В интерфейсах async не пишут вовсе.
Второй: await внутри метода без async. Так нельзя, компилятор выдаст ошибку и предложит добавить модификатор. В top-level statements await пишут прямо в Program.cs, но там асинхронный Main генерирует сам компилятор.
Механика: компилятор ищет у выражения метод GetAwaiter(), экземплярный или расширение. Полученный awaiter должен иметь IsCompleted, OnCompleted и GetResult(). Если задача уже завершена, код после await идёт синхронно, без переключения потока. Если нет, метод возвращает управление, а продолжение идёт на захваченном SynchronizationContext или в пуле потоков.
Зачем иногда убирают async: не строится машина состояний, меньше аллокаций. Цена:
- исключения: в методе без
asyncпроверка аргументов бросит исключение сразу при вызове, а не приawait; usingиtry: если вернуть задачу из блокаusing, ресурс освободится до окончания операции;- стек вызовов: метод пропадает из трассировки, отлаживать сложнее.
Правило: убирать async только в однострочных прокси без using, try и логики вокруг.
Где спотыкаются
Говорят, что await можно писать в любом методе, возвращающем Task. Модификатор async нужен методу, в котором есть await, а не тому, кого ждут.
Думают, что Task в сигнатуре уводит метод в фон. Его код выполняется синхронно на вызывающем потоке, пока не дойдёт до незавершённой операции.
Вместо await вызывают .Result или GetAwaiter().GetResult(). В WPF, WinForms и классическом ASP.NET это частая причина дедлока из-за контекста синхронизации, в ASP.NET Core контекста нет, но поток пула простаивает.