当前位置: 首页 > news >正文

Task.Run +Task.WhenAll 与 Paraller

在C#中,Task.Run配合Task.WhenAllParallel类都是用于并行处理以提高性能的常见方法,但它们的使用场景和内部机制有所不同。

1. Task.Run + Task.WhenAll

这种方法适用于I/O密集型操作(如网络请求、文件读写等)或CPU密集型操作,但更侧重于异步操作。它通过将多个任务并行启动,然后等待所有任务完成。
使用场景

  • 当操作是异步的(如使用async/await)时,这种方法更自然。
  • 每个任务相对独立,不需要共享资源(如果共享资源,需要注意线程安全)。
  • 任务数量不是特别大(虽然可以创建很多任务,但要注意资源限制)。

2. Parallel类

Parallel类(Parallel.ForParallel.ForEach)主要用于数据并行,适用于CPU密集型操作,它使用多个线程来并行处理数据集合。它是基于任务的,但内部使用线程池,并且是同步的(阻塞当前线程直到所有操作完成)。
使用场景

  • CPU密集型操作,例如大量计算。
  • 处理集合中的每个元素,且每个元素的处理是独立的(或通过线程安全的方式共享状态)。
  • 当操作是同步的,并且你希望利用多核处理器。

在C#中,Task.Run + Task.WhenAllParallel 类都是并行处理的技术,但适用场景和实现方式不同。以下是选择建议和对应的取消操作实现:


一、如何选择?

特性 Task.Run + Task.WhenAll Parallel
适用场景 I/O密集型操作、异步任务、独立任务 CPU密集型操作、数据并行处理
并行控制 手动控制(通过任务列表) 自动分区(通过ParallelOptions配置)
阻塞性 非阻塞(async/await) 阻塞(同步操作)
任务粒度 粗粒度(独立任务) 细粒度(数据集合元素)
异常处理 通过AggregateException捕获所有异常 同左
资源开销 较高(每个任务独立调度) 较低(优化线程池使用)

选择建议

  1. 优先用 Task.WhenAll

    • 处理 I/O密集型 操作(如API调用、文件读写)
    • 需要 异步等待 结果时(避免阻塞线程)
    • 任务逻辑 独立且数量动态变化
  2. 优先用 Parallel

    • 处理 CPU密集型 计算(如图像处理、数值计算)
    • 需要 高效处理数据集合(如数组、列表的并行循环)
    • 需要 限制并发度(通过MaxDegreeOfParallelism

二、取消操作实现

1. Task.Run + Task.WhenAll 的取消

使用 CancellationTokenSource 传递取消令牌。

public async Task RunTasksWithCancellationAsync()
{var cts = new CancellationTokenSource();// 创建任务列表(传入取消令牌)var tasks = new List<Task>();for (int i = 0; i < 10; i++){tasks.Add(Task.Run(() => DoWorkAsync(cts.Token), cts.Token));}// 外部触发取消(例如超时或用户操作)cts.CancelAfter(TimeSpan.FromSeconds(5)); // 5秒后自动取消try{await Task.WhenAll(tasks);}catch (OperationCanceledException){Console.WriteLine("任务已取消");}
}private async Task DoWorkAsync(CancellationToken token)
{while (!token.IsCancellationRequested){await Task.Delay(1000, token); // 模拟异步操作token.ThrowIfCancellationRequested(); // 检查取消}
}

2. Parallel 的取消

通过 ParallelOptions 传递取消令牌。

public void RunParallelWithCancellation()
{var cts = new CancellationTokenSource();var options = new ParallelOptions{CancellationToken = cts.Token,MaxDegreeOfParallelism = 4 // 限制并发数};cts.CancelAfter(TimeSpan.FromSeconds(5)); // 5秒后取消try{Parallel.For(0, 100, options, (i, state) =>{options.CancellationToken.ThrowIfCancellationRequested();DoCpuBoundWork(i); // 模拟CPU密集型操作});}catch (OperationCanceledException){Console.WriteLine("并行循环已取消");}
}private void DoCpuBoundWork(int index)
{Thread.Sleep(500); // 模拟CPU工作
}

三、关键注意事项

  1. 资源释放
    • 在取消后及时释放资源(如数据库连接、文件句柄)。
  2. 取消响应
    • 在循环或长时间操作中 定期检查 token.IsCancellationRequested
  3. 异常聚合
    • 两者都会抛出 AggregateException,需遍历 InnerExceptions 处理具体错误。
  4. 异步兼容性
    • Parallel 不支持 async 委托(内部用同步方法),若需异步并行循环,使用 Task.WhenAll

四、总结

  • Task.WhenAll:适合 异步、I/O密集型、异构任务
  • Parallel:适合 同步、CPU密集型、同构数据并行
  • 取消机制:统一通过 CancellationToken 实现,注意在任务内部定期检查取消状态。
http://www.sczhlp.com/news/13913/

相关文章:

  • 短线心得
  • 深度解析分散化与再平衡策略的实战奥秘-python基金分析
  • Langchain4j-2-ChatMemory
  • Langchain4j-1-流式输出
  • 将安卓手机中的应用提取出APK安装包的工具
  • Langchain4j-7-MCP
  • Langchain4j-6-RAG
  • 2025.8.16学习日记
  • vue3学习d1
  • HZ CSP-S模拟13
  • 在C程序中实现类似Redis的SCAN机制的LevelDB大规模key分批扫描
  • 手机信息查看APP——Device Info HW
  • 在Python程序中实现LevelDB的海量key的分批次扫描
  • 腾讯云机器翻译接口调用
  • 自定义菜单项
  • java异步判断线程池所有任务是否执行完
  • soket5隧道搭建
  • 【ARM Trace32(劳特巴赫) 使用介绍 2 -- Trace32 cmm 脚本基本语法及常用命令】
  • 这是一个随笔
  • freertos任务切换代码分析
  • Mybatis拦截器实现公共字段填充
  • Java Spring Boot监听事件和处理事件
  • Swagger Editor
  • Flow Matching
  • 【LGR-236-Div.2】洛谷 8 月月赛 II IAMOI Round #2
  • ABC419 补题
  • 智慧农业(数字化转型)
  • 神奇海螺 能不能好好说话
  • 设计表 Design table _3 修改单元格内容
  • tryhackme - 导言