【问题标题】:Parallel execution of a loop that uses async并行执行使用 async 的循环
【发布时间】:2014-12-31 19:09:17
【问题描述】:

我正在编写一个 Windows 服务,并且正在寻找一种方法来并行执行多个 foreach 循环,其中每个循环都会调用一个异步 (TAP) 方法。我最初尝试了以下代码,它不起作用,因为 Parallel.ForEach 和 async/await 不兼容。有谁知道是否有替代方法可以实现这一目标?

Parallel.ForEach(messagesByFromNumber, async messageGroup =>
{
    foreach (var message in messageGroup)
    {
        await message.SendAsync();
    }
});

为了清楚起见,由于 SendAsync() 的操作方式,foreach 循环的每个副本都必须串行执行;换句话说,foreach 循环不能并发/并行。

【问题讨论】:

  • 我不完全相信你会需要并行,因为异步调用是一种即发即忘类型的方法。只需为每个标准做一个标准并触发 async 方法应该做一些非常接近你想要它做的事情
  • @theDarse 我不能使用标准 foreach 作为外循环的原因是因为 SendAsync() 方法太慢了,以至于我需要外循环有机会在单独的线程上运行。执行两个嵌套的标准 foreach 循环将花费太长时间。
  • 不要混合并行和异步代码。当您不想烧毁线程(通常是 I/O 调用)时使用异步,并行用于在所有内核上并行执行 CPU 密集型计算。

标签: c# asynchronous concurrency parallel-processing async-await


【解决方案1】:

如果您的目标是同时运行这些,则无需使用Parallel.Foreach。只需检查所有组,为执行foreachSendAsync 的每个组创建一个任务,获取所有任务,然后使用Task.WhenAll 一次完成await 它们:

var tasks = messagesByFromNumber.Select(async messageGroup =>
{
    foreach (var message in messageGroup)
    {
        await message.SendAsync();
    }
});
await Task.WhenAll(tasks)

【讨论】:

  • 我不知道可以在 select 语句中以这种方式使用异步。刚刚尝试了您的解决方案,代码按需要运行。非常感谢!
  • @JeffGlazier 确定...随时。
【解决方案2】:

您可以使用AsyncEnumerator NuGet Package 使其更加简洁:

using System.Collections.Async;

await messagesByFromNumber.ParallelForEachAsync(async messageGroup =>
{
    foreach (var message in messageGroup)
    {
        await message.SendAsync();
    }
}, maxDegreeOfParallelism: 10);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多