我有一个异步方法,GetExpensiveThing()
,它执行一些昂贵的I/O操作。以下是我使用它的方式:
// Serial execution
public async Task<List<Thing>> GetThings()
{
var first = await GetExpensiveThing();
var second = await GetExpensiveThing();
return new List<Thing>() { first, second };
}
但由于这是一种昂贵的方法,我希望可以并行执行这些调用。我本以为移动 "await" 就能解决这个问题:
// Serial execution
public async Task<List<Thing>> GetThings()
{
var first = GetExpensiveThing();
var second = GetExpensiveThing();
return new List<Thing>() { await first, await second };
}
那个方法没用,所以我用一些任务包装它们,这个方法可以用:
// Parallel execution
public async Task<List<Thing>> GetThings()
{
var first = Task.Run(() =>
{
return GetExpensiveThing();
});
var second = Task.Run(() =>
{
return GetExpensiveThing();
});
return new List<Thing>() { first.Result, second.Result };
}
我甚至尝试在任务中使用awaits和async,但它变得非常混乱,并且没有成功。
有更好的方法以并行方式运行异步方法吗?还是任务是一个不错的方法?
async
函数中的 Continuations 是在捕获的上下文中调度的。但在大多数情况下,这个上下文是默认的SynchronizationContext
,它将 Continuations 调度到线程池中,导致它们并行运行。即使在 WPF 和 ASP 应用程序中,你也可以通过使用ConfigureAwait(false)
来解决这个问题。Task.Run
用于 CPU 绑定任务,并不需要它来并行运行 Continuations。 - V0ldek