Асинхронный Mетод без async в C#
Недавно я изменил сигнатуру метода действия контроллера следующим образом:
public async Task GetRecordAsync(int id)
=> await repo.GetAsync(id);
на
public Task GetRecordAsync(int id)
=> repo.GetAsync(id);
Во время код-ревью члены моей команды быстро заметили это и поставили под сомнение удаление ключевых слов async и await. Сначала я согласился, что это выглядит сомнительно. Даже после объяснения, которое приведено ниже, может быть полезно их вернуть, чтобы другие на этом не спотыкались.
Итак, мы можем безопасно опустить async/await, поскольку вызывающий метод GetRecordAsync в конечном итоге возвращает то же, что и вызываемый, repo.GetAsync. Вместо того, чтобы наш метод ожидал завершения задачи и возвращал результат, он передаёт эту работу вызывающей стороне.
Вы всегда можете ожидать Task, потому что он предоставляет API обратного вызова, который позволяет платформе сообщать, какой код выполнять после завершения асинхронной операции.
Подробнее про работу async/await
Удаление ключевых слов async/await предотвращает создание конечного автомата. Это немного снижает накладные расходы на выполнение метода. Хотя я не удивлюсь, если компилятор достаточно умён, чтобы оптимизировать этот момент.
Ловушки отсутствия async/await
1. Отсутствие методов в трассировке стека
Рассмотрим следующую цепочку методов:
static async Task Top() => await Middle();
static Task Middle() => Bottom();
static async Task Bottom() {
await Task.Delay(10);
throw new Exception("Bottom Exception");
}
При вызове Top(), трассировка стека не будет включать вызов Middle():
System.Exception: Bottom Exception
at ConsoleApp1.Bottom()
at ConsoleApp1.Top()
at ConsoleApp1.Program.Main(String[] args)
2. Отмена Заданий при Использовании using
Код ниже приводит к ошибке TaskCanceledException:
Task<string> Using HttpClient() {
using var client = new HttpClient();
return client.GetStringAsync("https://1.1.1.1");
}Это происходит потому, что объект HttpClient удаляется до того, как завершается асинхронный запрос, тем самым отменяя все текущие запросы.
Итого
В общем случая я бы не рекомендовал удалять async/await. Как говорится, преждевременная оптимизация - это корень зла. Можно рассмотреть удаление ключевых слов, если:
- Асинхронный метод - это просто звено в цепочке вызовов.
- Метод находится на «горячем» участке кода.
Источник: https://drakelambert.dev/2020/07/Asynchronous-Method-Without-async-in-C%23