




Parallel.ForEach 不保证执行顺序且不提供线程安全,而 foreach 严格保序;需用并发集合或异步任务队列替代共享变量操作,小数据量或IO密集场景不宜使用。
这是最直观、也最容易踩坑的区别。如果你写 Console.WriteLine(item) 测试,foreach 输出永远是 1→2→3→4;而 Parallel.ForEach 可能输出 3→1→4→2,甚至每次运行都不一样。
Parallel.ForEach 会出错foreach + 异步任务队列,或用 AsParallel().ForAll()(但依然不保序)Parallel.ForEach 本身是线

sharedList.Add(item),大概率会抛 ArgumentException 或数据丢失。
Collection was modified; enumeration operation may not execute. 或结果数量少于输入项数ConcurrentBag、ConcurrentQueue,或加 lock(但锁太重会抵消并行收益)List.ForEach 是单线程的,天然没这问题,但它也不是 Parallel.ForEach 的替代品(类型受限、不支持异步)小数据(比如 Parallel.ForEach 往往比 foreach 慢——线程创建、调度、同步开销压过了计算收益。
ProcessHeavy(item) 类型任务(CPU 密集,单次 > 10ms),数据量 ≥ 数千Parallel.ForEachAsync 处理异步 IO,它比手动 Task.WhenAll 更可控(可设最大并发数、支持 CancellationToken)await Parallel.ForEachAsync(myList, new ParallelOptions { MaxDegreeOfParallelism = 10 }, async (item, token) =>
{
await CallApiAsync(item, token);
});
别被“并行”二字带偏。90% 的业务逻辑需要顺序、可预测、易调试。比如“依次上传文件并记录日志”“按顺序更新数据库字段”,这时 foreach 配合 await 是最稳妥的选择。
Task.WhenAll 或上面提到的 Parallel.ForEachAsync,而不是硬套 Parallel.ForEach + async void
list.ForEach(async item => await ...) 是危险写法——编译器会转成 async void,异常无法捕获,千万别用