Task.WhenAll的顺序版本

时间:2015-05-18 14:55:47

标签: c# async-await

是否存在与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.FindAsyncdbcontext.Set<T>().FindAsync

的抽象

您可以执行await context.Set<Foo>().Where(f => command.Foos.Contains(f.Id)).ToListAsync()但示例已经简化

1 个答案:

答案 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));