0

0

c# ForAll 和 ForEach 在PLINQ中的区别

月夜之吻

月夜之吻

发布时间:2026-01-03 02:37:28

|

328人浏览过

|

来源于php中文网

原创

ForAll是PLINQ专属的无返回、不保序、不合并结果的并行消费方法,仅用于ParallelQuery末端;ForEach是IEnumerable/List的顺序遍历方法,ParallelQuery上不存在该方法。

c# forall 和 foreach 在plinq中的区别

ForAll 是 PLINQ 专属的并行消费方法,ForEach 是普通集合的顺序遍历

ForAll 只存在于 ParallelQuery(即调用 AsParallel() 后的查询结果),它不返回值、不保证执行顺序、也不合并结果——每个线程拿到自己的数据块后立刻执行委托,完事就退出。ForEach 则是 IEnumerableList 上的实例方法,纯顺序执行,线程安全需自行保障,且会等全部元素处理完才返回。

  • ForAll 不能链式返回新集合,只适合“发通知”“写日志”“更新非共享状态”这类无返回、无依赖的操作
  • ForEach 在 PLINQ 中根本不存在——你写 list.AsParallel().ForEach(...) 会编译失败,因为 ParallelQuery 没有这个方法;真正能用的是 Parallel.ForEach(...)(来自 System.Threading.Tasks.Parallel),但那是另一套 API,和 LINQ 风格无关
  • 别把 Parallel.ForEachParallelQuery.ForAll 混为一谈:前者接受 IEnumerable 或分区器,后者只接受 ParallelQuery

为什么 ForAll 不保证顺序?这和 PLINQ 的分区机制直接相关

PLINQ 把源集合切分成若干段(partition),分给不同线程处理。这些段大小不固定、分配时机不确定、完成时间也不同。ForAll 就是让每个线程在自己分到的那块数据上“立刻开干”,不做任何等待或排序协调——所以输出顺序完全不可预测。

  • 如果你需要顺序输出(比如写入文件、生成有序报告),ForAll 不适用;该用 foreach 遍历 ToArray()ToList() 结果
  • ForAll 内部跳过结果合并步骤,因此比 ToArray() + foreach 快,尤其在数据量大、操作耗时长时优势明显
  • 若委托里访问了共享变量(如静态计数器、全局 list),必须加锁或改用线程安全类型(如 ConcurrentBag),否则结果错乱

常见误用:想并行又想要顺序,结果既慢又错

典型错误是这样写:

numbers.AsParallel()
    .Where(n => IsPrime(n))
    .OrderBy(n => n) // 强制全缓冲 + 排序合并
    .ForAll(Console.WriteLine); // 以为能按序打印素数

问题在于:OrderBy 会让 PLINQ 缓冲所有结果再排序,彻底抵消并行优势;而 ForAll 仍不保证输出顺序(即使输入已排序,多线程并发写控制台也会乱序)。

Fotor AI Face Generator
Fotor AI Face Generator

Fotor 平台的在线 AI 头像生成器

下载
  • 要顺序输出:去掉 ForAll,改用 foreach (var x in query.OrderBy(...)) Console.WriteLine(x);
  • 要纯并行处理 + 丢弃结果:保留 ForAll,但删掉 OrderBy 等强制合并的运算符
  • 想边算边处理?PLINQ 默认“部分缓冲”,可用 WithMergeOptions(ParallelMergeOptions.NotBuffered) 让结果更早流出,但仍不保序

ForEach 方法名重复导致的认知陷阱

名字都叫 ForEach,但实际是三个不同东西:

  • List.ForEach():实例方法,顺序,单线程,属于 .NET Framework 2.0 就有的老 API
  • Parallel.ForEach():静态方法,接受 IEnumerable 或自定义分区器,可配置并行度、取消令牌等,属于 TPL
  • ParallelQuery.ForAll():扩展方法,仅用于 PLINQ 查询链末端,无返回、无合并、不保序

它们之间没有继承或重载关系,只是命名巧合。选哪个,取决于你手头的数据类型和目标:是已有集合想并行遍历?用 Parallel.ForEach;是 LINQ 查询想加速过滤+消费?用 AsParallel().Where(...).ForAll(...);只是简单循环打印?foreach 最稳。

相关专题

更多
数据类型有哪几种
数据类型有哪几种

数据类型有整型、浮点型、字符型、字符串型、布尔型、数组、结构体和枚举等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

298

2023.10.31

php数据类型
php数据类型

本专题整合了php数据类型相关内容,阅读专题下面的文章了解更多详细内容。

216

2025.10.31

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1436

2023.10.24

Go语言中的运算符有哪些
Go语言中的运算符有哪些

Go语言中的运算符有:1、加法运算符;2、减法运算符;3、乘法运算符;4、除法运算符;5、取余运算符;6、比较运算符;7、位运算符;8、按位与运算符;9、按位或运算符;10、按位异或运算符等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

226

2024.02.23

php三元运算符用法
php三元运算符用法

本专题整合了php三元运算符相关教程,阅读专题下面的文章了解更多详细内容。

85

2025.10.17

php中foreach用法
php中foreach用法

本专题整合了php中foreach用法的相关介绍,阅读专题下面的文章了解更多详细教程。

37

2025.12.04

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

473

2023.08.10

Python 多线程与异步编程实战
Python 多线程与异步编程实战

本专题系统讲解 Python 多线程与异步编程的核心概念与实战技巧,包括 threading 模块基础、线程同步机制、GIL 原理、asyncio 异步任务管理、协程与事件循环、任务调度与异常处理。通过实战示例,帮助学习者掌握 如何构建高性能、多任务并发的 Python 应用。

131

2025.12.24

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

150

2025.12.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PHP新手语法线上课程教学
PHP新手语法线上课程教学

共13课时 | 0.8万人学习

光速学会docker容器
光速学会docker容器

共33课时 | 1.8万人学习

时间管理,自律给我自由
时间管理,自律给我自由

共5课时 | 0.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号