У вас уже есть несколько хороших ответов, которые описывают , как async
не делает вещи асинхронными, как async
методы начинают выполняться синхронно, и как await
может действовать синхронно, если его задача уже выполнена .
Итак, давайте поговорим о дизайне.
internal Task<IList<Foo>> GetAllFooAsync()
{
// this is actually fake-async due to legacy code.
var result = SomeSyncMethod();
return Task.FromResult(result);
}
Как уже отмечалось, это синхронный метод , но он имеет асинхронную сигнатуру. Это смущает; если метод не асинхронный, лучше использовать синхронный API:
internal IList<Foo> GetAllFoo()
{
// this is actually fake-async due to legacy code.
var result = SomeSyncMethod();
return result;
}
и аналогичный метод, который его вызывает:
public IList<Foo> GetFilteredFoo()
{
var allFoos = GetAllFoo();
return allFoos.Where(x => x.IsFiltered);
}
Так что теперь у нас есть синхронные реализации с синхронными API. Вопрос сейчас о потреблении. Если вы используете это из ASP.NET, я рекомендую использовать их синхронно. Однако, если вы используете их из приложения с графическим интерфейсом, вы можете использовать Task.Run
, чтобы перенести синхронную работу в поток пула потоков, а затем обработать ее, как если бы она была асинхронной:
var someRepo = new SomeRepo();
var filteredFoos = Task.Run(() => someRepo.GetFilteredFoo()); // no await
// a couple of additional async calls (to other classes) without await..
// .. followed by:
await Task.WhenAll(filteredFoos, otherTask, anotherTask).ConfigureAwait(false);
В частности, я не рекомендую использовать Task.Run
для реализации, например, GetAllFooAsync
. Вы должны использовать Task.Run
для вызова методов, а не для их реализации , а Task.Run
в основном следует использовать для вызова синхронного кода из потока GUI (т. Е. Не в ASP.NET).