【问题标题】:Must we wait for all async calls when using Parallel.Foreach?使用 Parallel.Foreach 时我们必须等待所有异步调用吗?
【发布时间】:2018-12-24 12:25:53
【问题描述】:

假设我们有一个过滤器列表,是否可以使用 Parallel.ForEach 进行异步调用然后使用它们?我们必须等待所有呼叫结束吗?如果我们有 3 个异步调用而一个失败/超时怎么办?

var results = new ConcurrentBag<Service>();

Parallel.ForEach(filters, async filter =>
{
   var result = await serviceClient.GetAllAsync(filter).ConfigureAwait(false);

   results.AddRange(result);
});

MyMapper.Map(results);

MyMapper 有一个方法的地方:

Map(IEnumerable<Service> services) {
   foreach(Service service in services) {
      //do stuff
   }
}

【问题讨论】:

  • 您将拥有多少个过滤器?
  • 你首先不需要Parallel.ForEach。你想要await Task.WhenAll(filters.Select(filter =&gt; serviceClient.GetAllAsync(filter)))

标签: c# parallel-processing async-await parallel.foreach


【解决方案1】:

Parallel 库被认为可以并行处理数百万个项目。在那里使用Parallel.ForEach 不会有任何改进。你可以改用Task.WhenAll

var tasks = new List<Task>();

foreach(var filter in filters)
{
   tasks.Add(serviceClient.GetAllAsync(filter));
}

results.AddRange(await Task.WhenAll(tasks).ConfigureAwait(false));

你可以做一些 LinQ。我没有,所以这个想法更清楚。 使用此代码,您可以获得一定程度的并行性,await 将帮助您处理异常。

【讨论】:

  • results.Add(await task); 的意义何在?您正在等待完成的任务。只需得到Task.WhenAll的结果
  • @FCin 不是我的代码示例。我一直在做一些代码审查。我注意到我们的解决方案的许多部分都有一些await Task.WhenAll。 :-(
  • OP 将通过并行执行服务调用来提高性能。但是,在不同的内核上执行它会浪费线程什么都不做(因为我假设服务调用访问一些外部资源),这些线程只会等待响应。 async-await 通过仅使用一个线程提供几乎“并行”的方法。
【解决方案2】:

我会做一些不同的事情。假设

serviceClient.GetAllAsync(filter)

在不同的线程/任务中做某事或对某个 url 发出请求,我认为没有必要使用 Paralle.ForEach。

我要做的是创建一个任务列表并使用 Task.WaitAll 方法调用它们。这样您就可以处理错误任务的任何异常。

用于此的代码 sn-p 将类似于以下内容:

  var queryService = filters.Select(x => sClient.GetAllAsync()).ToArray();

        try
        {
            // Wait for all the tasks to finish.
            Task.WaitAll(queryService);
        }
        catch (AggregateException e)
        {
            //At least one of the Task instances was canceled.
            //If a task was canceled, the AggregateException contains an OperationCanceledException in its InnerExceptions collection.
        }

【讨论】:

  • 不,你应该使用await Task.WhenAll来保持异步代码
猜你喜欢
  • 1970-01-01
  • 2019-10-09
  • 2020-03-10
  • 2023-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多