news 2026/7/23 11:31:10

C#中多线程异步操作的方法-Parallel.ForEachAsync

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C#中多线程异步操作的方法-Parallel.ForEachAsync

1. 核心概念

Parallel.ForEachAsync是在.NET 6中引入的方法。
它的核心作用是:对一组数据执行异步操作,并且同时控制并发数量(也就是同时跑多少个任务)
它完美解决了两个痛点:

  1. 传统的Parallel.ForEach不支持async/await(它是为阻塞式 CPU 任务设计的)。
  2. 直接用Task.WhenAll(tasks)会一次性把所有任务扔出去,如果数据有 10 万条,会瞬间耗尽内存或网络端口。

2. 基本语法与关键参数

publicstaticTaskForEachAsync<TSource>(thisIEnumerable<TSource>source,ParallelOptionsparallelOptions,Func<TSource,CancellationToken,ValueTask>body)

关键参数说明

  • source:数据源(如数组、List、或你用Chunk()切分出的块)。
  • parallelOptions:并行配置项,极其重要,包含两个核心属性:
    • MaxDegreeOfParallelism最大并发数。比如设为 5,表示最多同时运行 5 个异步任务,完成一个再补一个。
    • CancellationToken:取消令牌,用于中途终止所有并发任务。
  • body:要执行的异步逻辑(注意返回类型是ValueTask,不是Task,性能更好)。

3. 经典示例

示例 1:批量并发下载网页/API请求(最常见场景)

假设我们要下载 100 个网页,如果串行可能需要 1 分钟,但如果同时开 10 个并发,只需 6 秒。

usingSystem.Net.Http;List<string>urls=GetUrls();// 假设有 100 个 URLusingHttpClientclient=newHttpClient();// 配置并行选项:最大并发 10varoptions=newParallelOptions{MaxDegreeOfParallelism=10};Console.WriteLine("开始并发下载...");awaitParallel.ForEachAsync(urls,options,async(url,ct)=>{try{// 传入 ct,如果外部取消,当前请求会立即中止stringcontent=awaitclient.GetStringAsync(url,ct);Console.WriteLine($"成功下载{url},长度:{content.Length}");}catch(OperationCanceledException){// 被取消}catch(Exceptionex){Console.WriteLine($"下载失败{url}:{ex.Message}");}});Console.WriteLine("全部下载完成。");

示例二:收集结果

ForEachAsync 本身没有返回值(返回 Task),如果需要收集处理结果,必须使用线程安全集合(如 ConcurrentBag 或 ConcurrentQueue)。**

usingSystem.Collections.Concurrent;usingSystem.Diagnostics;publicstaticasyncTaskExample_WithResultCollection(){varinputs=Enumerable.Range(1,10);varresults=newConcurrentBag<int>();// 线程安全集合awaitParallel.ForEachAsync(inputs,asynci=>{awaitTask.Delay(100);// 模拟耗时操作intresult=i*i;// 计算逻辑results.Add(result);// 并发添加结果(线程安全)Console.WriteLine($"{DateTime.Now:mm:ss:fff}- 处理{i}");});Console.WriteLine($"结果数量:{results.Count}");}

示例三:配合取消令牌

在用户关闭窗口或点击“停止”按钮时优雅地停止处理。

publicstaticasyncTaskExample_WithCancellation(CancellationTokencts){varrange=Enumerable.Range(0,1000);try{awaitParallel.ForEachAsync(range,newParallelOptions{CancellationToken=cts,MaxDegreeOfParallelism=10},async(i,ct)=>{// 如果外部取消,这里会抛出 OperationCanceledExceptionawaitTask.Delay(100,ct);Console.WriteLine($"处理中:{i}");});}catch(OperationCanceledException){Console.WriteLine("任务被用户取消。");}}

4. 核心优势对比表

特性foreach+awaitTask.WhenAllParallel.ForEachAsync
执行方式串行(一个接一个)全量并发(同时启动所有)可控并发(池化执行)
内存/资源占用极低极高(容易内存溢出/端口耗尽)适中(按需启动)
总耗时最长最短(如果不崩溃的话)较短(与并发数成正比)
支持取消支持支持完美支持

5. 注意事项与避坑指南

  1. 必须限制并发数
    不设置MaxDegreeOfParallelism时,默认可能会使用处理器数量作为并发度。对于网络请求,建议显式设置为520之间(根据目标服务器的承受能力和你的网络带宽决定),防止把对方服务器打挂,或触发对方防爬机制被封 IP。

  2. 线程安全问题(最容易踩的坑)
    在并发环境下,Parallel.ForEachAsync的内部相当于多线程同时运行。如果你在里面修改了 UI 绑定的集合(如ObservableCollection)或普通的计数字典,极大概率会报错或数据错乱

    • 集合操作:使用ConcurrentDictionaryConcurrentBag,或者用lock
    • UI 更新:如果要在里面更新 WPF/WinForms 的 UI,需要使用Dispatcher.Invoke
  3. 异常处理

    • 如果在循环体内抛出异常(且未 catch 吞掉),Parallel.ForEachAsync会将异常包装进AggregateException抛出。
    • 如果你想让某个任务失败不影响其他任务,就在循环体内部try-catch吞掉单次异常。
    • 如果收到CancellationToken,必须立即停止并抛出OperationCanceledException
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/23 11:24:39

Python毕设项目:基于 Python 的数字化数学自主学习测评管理系统 自适应数学练习与成绩统计系统 (源码+文档,讲解、调试运行,定制等)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/7/23 11:23:29

Windows平台AI助手的本地化部署与安全实践

1. Windows平台AI助手的范式革新 当OpenClaw的Windows版本WinClaw首次出现在我的任务栏时&#xff0c;我意识到这不仅仅是又一个AI助手。与那些依赖云端服务的"智能管家"不同&#xff0c;它安静地驻留在系统托盘&#xff0c;却拥有对整个操作系统的完全掌控权——从文…

作者头像 李华
网站建设 2026/7/23 11:22:50

基于深度学习的轴承故障智能诊断算法解析

1. 项目概述在工业设备维护领域&#xff0c;轴承故障诊断一直是个技术难点。传统方法依赖人工经验判断&#xff0c;效率低且容易误判。这套OCSSA-VMD-Transformer-BiLSTM-Adaboost组合算法&#xff0c;通过多模态信号处理和深度学习技术&#xff0c;实现了轴承故障的智能诊断。…

作者头像 李华
网站建设 2026/7/23 11:22:18

KVM虚拟化技术详解:从原理到企业级实践

1. KVM虚拟化技术概述 KVM&#xff08;Kernel-based Virtual Machine&#xff09;作为Linux内核的原生虚拟化解决方案&#xff0c;已经彻底改变了我们在x86硬件上运行虚拟机的方式。不同于传统的Type-2虚拟化方案&#xff08;如VirtualBox&#xff09;&#xff0c;KVM直接将自己…

作者头像 李华
网站建设 2026/7/23 11:21:33

BQ24810充电管理芯片寄存器配置实战:从原理到应用避坑指南

1. 项目概述与核心价值在笔记本电脑、移动电源、便携式医疗设备等产品的电源系统设计中&#xff0c;充电管理芯片扮演着“心脏”和“大脑”的双重角色。它不仅要高效地将适配器能量输送给电池和系统&#xff0c;还必须确保整个过程安全、可靠&#xff0c;并能智能应对各种动态负…

作者头像 李华