You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中如何用Parallel替代Zip实现异步任务并行处理?

解决Parallel.ForEachAsync处理多参数异步任务的问题

你的核心问题是没有正确将offsets和prices的配对数据传递给Parallel.ForEachAsync,同时原代码存在语法和逻辑错误。以下是具体的解决步骤和正确实现:

错误原因分析

  1. 错误的Zip用法:你在Zip的lambda中直接await Func(offset, price),这会让Zip返回IEnumerable<Task<(decimal, decimal)?>>,而Parallel.ForEachAsync需要遍历的是原始数据对,而非预先创建的任务集合。
  2. 语法不完整:Parallel.ForEachAsync的调用缺少异步委托参数,且括号未闭合;另外它返回的是ValueTask<ParallelLoopResult>,必须用await等待完成。

正确实现方式

1. 先打包数据对

首先用Zip将offsets和prices合并为包含两个参数的元组集合,这一步不需要提前执行异步方法:

// 将两个数组的元素配对成元组集合
var valuePairs = offsets.Zip(prices, (offset, price) => (Offset: offset, Price: price));

2. 无结果收集的场景

如果不需要保存每个任务的执行结果,直接遍历配对集合并执行异步方法:

// 注意Parallel.ForEachAsync返回ValueTask,需要await
ParallelLoopResult result = await Parallel.ForEachAsync(valuePairs, async (pair, ct) =>
{
    // 传入配对后的两个参数执行异步方法
    await Func(pair.Offset, pair.Price);
});

3. 需要收集结果的场景

如果要保存每个Func的返回值,由于Parallel.ForEachAsync是并发执行的,必须使用线程安全集合(比如ConcurrentBag)来存储结果:

// 线程安全集合用于存储并发执行的结果
var results = new ConcurrentBag<(decimal, decimal)?>();

await Parallel.ForEachAsync(valuePairs, async (pair, ct) =>
{
    var taskResult = await Func(pair.Offset, pair.Price);
    results.Add(taskResult);
});

// 按需转换为数组或列表
(decimal, decimal)?[] resultArray = results.ToArray();

额外说明

  • Parallel.ForEachAsync会自动根据系统资源控制并发度,默认并发数等于CPU核心数,你可以通过ParallelOptions手动调整:
    var options = new ParallelOptions { MaxDegreeOfParallelism = 4 };
    await Parallel.ForEachAsync(valuePairs, options, async (pair, ct) =>
    {
        await Func(pair.Offset, pair.Price);
    });
    
  • 与Task.WhenAll的区别:Task.WhenAll会一次性启动所有任务,而Parallel.ForEachAsync会动态调度任务,更适合处理大量数据或需要控制并发度的场景。

内容的提问来源于stack exchange,提问作者Nicolas REY

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 10:12:44