Самые Частые Ошибки при Работе с async/await. Продолжение 8-10
Начало
Часть 2
8. Синхронные ожидания
Если вы хотите ожидать асинхронное выражение в синхронном методе, вы должны переписать всю цепочку вызовов на асинхронную. Кажется, что более легкое решение - вызвать
Wait или Result для возвращаемой задачи. Но это будет стоить вам заблокированного потока и может привести к взаимной блокировке. Сделайте всю цепочку асинхронной. В консольном приложении допустим асинхронный метод Main, в контроллерах ASP.NET – асинхронные методы действия.❌ Неверно
void DoSomething() {
Thread.Sleep(1);
Task.Delay(2).Wait();
var result1 = GetAsync().Result;
var result2 = GetAsync().GetAwaiter().
GetResult();
var unAwaitedResult3 = GetAsync();
var result3 = unAwaitedResult3.Result;
}
✅ Верноasync Task DoSomething() {
await Task.Delay(1);
await Task.Delay(2);
var result1 = await GetAsync();
var result2 = await GetAsync();
}
9. Отсутствие ConfigureAwait(bool)По умолчанию, когда мы ожидаем асинхронную операцию, продолжение планируется с использованием захваченного
SynchronizationContext или TaskScheduler. Это приводит к дополнительным затратам и может привести к взаимной блокировке, особенно в WindowsForms, WPF и старых приложениях ASP.NET. Вызывая ConfigureAwait(false), мы гарантируем, что текущий контекст игнорируется при вызове продолжения. Подробнее о ConfigureAwait в серии постов с тегом #AsyncAwaitFAQ❌ Неверно
async Task DoSomethingAsync() {
await DoSomethingElse();
}
✅ Верноasync Task DoSomethingAsync() {
await DoSomethingElse().
ConfigureAwait(false);
}
10. Возврат null из метода, возвращающего TaskВозврат
null значения из синхронного метода типа Task/Task<> приводит к исключению NullReferenceException, если кто-то ожидает этот метод. Чтобы этого избежать, всегда возвращайте результат этого метода с помощью помощников Task.CompletedTask или Task.FromResult<T>(null).❌ Неверно
Task DoAsync() {
return null;
}
Task<object> GetSomethingAsync() {
return null;
}
Task<HttpResponseMessage>
TryGetAsync(HttpClient httpClient) {
return httpClient?.
GetAsync("/some/endpoint");
}
✅ ВерноTask DoAsync() {
return Task.CompletedTask;
}
Task<object> GetSomethingAsync() {
return Task.FromResult<object>(null);
}
Task<HttpResponseMessage>
TryGetAsync(HttpClient httpClient) {
return httpClient?.
GetAsync("/some/endpoint") ??
Task.FromResult(default(
HttpResponseMessage));
}
Продолжение следует…Источник: https://cezarypiatek.github.io/post/async-analyzers-p2/