Task.WhenAll的顺序版本

And*_*ers 2 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;
}
Run Code Online (Sandbox Code Playgroud)

编辑:对于投票结束的人,我想知道是否存在等待所有任务以异步但顺序方式完成的构建方式.

@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()

      ...
   }
}
Run Code Online (Sandbox Code Playgroud)

那会失败,但是

var foos = await context.AwaitAllAsync(command.Foos.Select(foo => context.FindAsync<Foo>(foo.Id));
Run Code Online (Sandbox Code Playgroud)

不会,context.FindAsync是一个抽象dbcontext.Set<T>().FindAsync

你可以这么做await context.Set<Foo>().Where(f => command.Foos.Contains(f.Id)).ToListAsync()但是这个例子很简单

Ste*_*ary 11

我认为核心的误解就是这种Task类型.在异步代码中,a Task始终在运行.所以这没有意义:

是否存在Task.WaitAll类似Task.WhenAll但不并行的非阻塞并发?

如果你有一系列任务,那么它们都已经开始了.

我想知道是否存在等待所有任务以异步但顺序方式完成的构建方式.

当然,你可以await按顺序进行.对此的标准模式是awaitforeach循环内部使用,就像您发布的方法一样.

但是,顺序await工作的唯一原因是因为您的LINQ查询被延迟评估.特别是,如果您重新启动任务集合,它将失败.这样可行:

var tasks = command.Foos.Select(foo => context.FindAsync<Foo>(foo.Id));
var foos = await context.AwaitAllAsync(tasks);
Run Code Online (Sandbox Code Playgroud)

这失败了:

var tasks = command.Foos.Select(foo => context.FindAsync<Foo>(foo.Id))
    .ToList();
var foos = await context.AwaitAllAsync(tasks);
Run Code Online (Sandbox Code Playgroud)

在内部,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));
Run Code Online (Sandbox Code Playgroud)

  • @Mick:如果您确实需要一个列表,那么您可以从通用方法派生类型,如下所示: `async Task&lt;List&lt;T&gt;&gt; MyFunc&lt;TId, T&gt;(this IEnumerable&lt;TId&gt; ids, Func&lt;TId , Task&lt;T&gt;&gt; f) { var ret = new List&lt;T&gt;(); foreach (var id in ids) ret.Add(await f(id)); 返回ret;}`。其中最困难的部分是确定如何命名“MyFunc”。它应该以“Async”结尾,并且还传达了它是顺序“await”,而不是并发“await”的含义。 (2认同)