ForAll是PLINQ专属的无返回、不保序、不合并结果的并行消费方法,仅用于ParallelQuery末端;ForEach是IEnumerable/List的顺序遍历方法,ParallelQuery上不存在该方法。
ForAll 只存在于 ParallelQuery(即调用 AsParallel() 后的查询结果),它不返回值、不保证执行顺序、也不合并结果——每个线程拿到自己的数据块后立刻执行委托,完事就退出。ForEach 则是 IEnumerable 或 List 上的实例方法,纯顺序执行,线程安全需自行保障,且会等全部元素处理完才返回。
ForAll 不能链式返回新集合,只适合“发通知”“写日志”“更新非共享状态”这类无返回、无依赖的操作ForEach 在 PLINQ 中根本不存在——你写 list.AsParallel().ForEach(...) 会编译失败,因为 ParallelQuery 没有这个方法;真正能用的是 Parallel.ForEach(...)(来自 System.Threading.Tasks.Parallel),但那是另一套 API,和 LINQ 风格无关Parallel.ForEach 和 ParallelQuery.ForAll 混为一谈:前者接受 IEnumerable 或分区器,后者只接受 ParallelQuery
PLINQ 把源集合切分成若干段(partition),分给不同线程处理。这些段大小不固定、分配时机不确定、完成时间也不同。ForAll 就是让每个线程在自己分到的那块数据上“立刻开干”,不做任何等待或排序协调——所以输出顺序完全不可预测。
ForAll 不适用;该用 foreach 遍历 ToArray() 或 ToList() 结果ForAll 内部跳过结果合并步骤,因此比 ToArray() + foreach 快,尤其在数据量大、操作耗时长时优势明显ConcurrentBag),否则结果错乱典型错误是这样写:
numbers.AsParallel()
.Where(n => IsPrime(n))
.OrderBy(n => n) // 强制全缓冲 + 排序合并
.ForAll(Console.WriteLine); // 以为能按序打印素数
问题在于:OrderBy 会让 PLINQ 缓冲所有结果再排序,彻底抵消并行优势;而 ForAll 仍不保证输出顺序
(即使输入已排序,多线程并发写控制台也会乱序)。
ForAll,改用 foreach (var x in query.OrderBy(...)) Console.WriteLine(x);
ForAll,但删掉 OrderBy 等强制合并的运算符WithMergeOptions(ParallelMergeOptions.NotBuffered) 让结果更早流出,但仍不保序名字都叫 ForEach,但实际是三个不同东西:
List.ForEach() :实例方法,顺序,单线程,属于 .NET Framework 2.0 就有的老 APIParallel.ForEach():静态方法,接受 IEnumerable 或自定义分区器,可配置并行度、取消令牌等,属于 TPLParallelQuery.ForAll() :扩展方法,仅用于 PLINQ 查询链末端,无返回、无合并、不保序它们之间没有继承或重载关系,只是命名巧合。选哪个,取决于你手头的数据类型和目标:是已有集合想并行遍历?用 Parallel.ForEach;是 LINQ 查询想加速过滤+消费?用 AsParallel().Where(...).ForAll(...);只是简单循环打印?foreach 最稳。