【发布时间】:2021-04-30 03:59:02
【问题描述】:
我有一个需要并行运行的循环,因为每次迭代都很慢且处理器密集,但我还需要调用异步方法作为循环中每次迭代的一部分。
我看到了有关如何在循环中处理异步方法的问题,但不是异步和同步的组合,这就是我所拥有的。
我的(简化的)代码如下 - 我知道由于异步操作被传递给 foreach,这将无法正常工作。
protected IDictionary<int, ReportData> GetReportData()
{
var results = new ConcurrentDictionary<int, ReportData>();
Parallel.ForEach(requestData, async data =>
{
// process data synchronously
var processedData = ProcessData(data);
// get some data async
var reportRequest = await BuildRequestAsync(processedData);
// synchronous building
var report = reportRequest.BuildReport();
results.TryAdd(data.ReportId, report);
});
// This needs to be populated before returning
return results;
}
当操作必须是异步的以等待单个异步调用时,有什么方法可以并行执行操作。
将同步函数转换为异步函数并不实用。
我不想将操作拆分并有一个 Parallel.ForEach,然后是带有 WhenAll 和另一个 Parallel.ForEach 的异步调用,因为每个阶段的速度在不同迭代之间可能会有很大差异,因此拆分它会效率低下因为较快的会在继续之前等待较慢的。
我确实想知道是否可以使用 PLINQ ForAll 代替 Parallel.ForEach 但从未使用过 PLINQ 并且不确定它是否会在返回之前等待所有迭代完成,即任务是否仍在运行进程结束。
【问题讨论】:
-
这能回答你的问题吗? Parallel.ForEach and async-await
-
Parallel.ForEachis not async-friendly,PLINQ 也不是。 AFAIK 处理混合同步-异步工作负载的理想工具是 TPL 数据流库。你可以看到一个例子here。请记住,TPL 数据流具有较小的学习曲线。如果您没有时间,您可以将ThreadPool与大量线程打包,并同步处理所有内容。 -
你能把异步调用转换成同步调用吗?使用 async/await 主要是为了隐藏 IO 操作的延迟,在并行运行时可能没有用。
-
@JonasH - 虽然异步在这里没有用,但在其他地方使用相同的方法并且异步在那里很有用;该方法最终调用了一个仅异步的库方法,因此更改它并不容易。
标签: c# async-await parallel-processing parallel.foreach plinq