是否存在与Task.WaitAll
类似的无阻塞Task.WhenAll
但不平行?
我写了这个,但也许是内置的?
public async Task<IEnumerable<T>> AwaitAllAsync<T>(IEnumerable<Task<T>> tasks)
{
List<T> result = new List<T>();
foreach(var task in tasks)
{
result.Add(await task);
}
return result;
}
编辑:对于投票结束的人,我想知道是否存在等待所有任务以异步但顺序方式完成的构建方式。
@Anders:那你就做了别的事。向我们展示您的代码
考虑这段代码
public class SaveFooCommandHandler : ICommandHandler<SaveFooCommand>
{
private readonly IBusinessContext context;
public SaveFooCommandHandler(IBusinessContext context)
{
this.context = context;
}
public async Task Handle(SaveFooCommand command)
{
var foos = (await Task.WhenAll(command.Foos.Select(foo => context.FindAsync<Foo>(foo.Id))).ToList()
...
}
}
那会失败,但是
var foos = await context.AwaitAllAsync(command.Foos.Select(foo => context.FindAsync<Foo>(foo.Id));
不会,context.FindAsync
是dbcontext.Set<T>().FindAsync
您可以执行await context.Set<Foo>().Where(f => command.Foos.Contains(f.Id)).ToListAsync()
但示例已经简化
答案 0 :(得分:10)
我认为核心误解是围绕Task
类型。在异步代码中,Task
始终已在运行。所以这没有意义:
是否存在类似于
Task.WaitAll
但与并行并发的非阻塞Task.WhenAll
?
如果您有一系列任务,则所有已经启动。
我想知道是否存在等待所有任务以异步但顺序方式完成的构建方式。
当然,你可以顺序await
。标准模式是在await
循环中使用foreach
,就像您发布的方法一样。
但是,顺序 - await
工作的唯一原因是因为您的LINQ查询被延迟评估。特别是,如果您重新启动任务集合,它将失败。所以这有效:
var tasks = command.Foos.Select(foo => context.FindAsync<Foo>(foo.Id));
var foos = await context.AwaitAllAsync(tasks);
然后失败了:
var tasks = command.Foos.Select(foo => context.FindAsync<Foo>(foo.Id))
.ToList();
var foos = await context.AwaitAllAsync(tasks);
在内部,Task.WhenAll
会激活您的任务序列,以便它知道需要等待多少任务。
但这不是重点。您尝试解决的真正问题是如何串行执行异步代码,这最容易使用foreach
完成:
var foos = new List<Foo>();
foreach (var fooId in command.Foos.Select(f => f.Id))
foos.Add(await context.FindAsync<Foo>(fooId));