Parallel.ForEach 不保证执行顺序且不提供线程安全,而 foreach 严格保序;需用并发集合或异步任务队列替代共享变量操作,小数据量或IO密集场景不宜使用。

Parallel.ForEach 会乱序,foreach 一定按顺序
这是最直观、也最容易踩坑的区别。如果你写 Console.WriteLine(item) 测试,foreach 输出永远是 1→2→3→4;而 Parallel.ForEach 可能输出 3→1→4→2,甚至每次运行都不一样。
- 原因:多个线程并行执行,谁先完成谁先输出,没有调度保证
- 后果:如果逻辑依赖顺序(比如累加到同一个变量、写入文件需严格编号),直接用
Parallel.ForEach会出错 - 补救方式:不推荐“强行排序”,而是改用
foreach+ 异步任务队列,或用AsParallel().ForAll()(但依然不保序)
线程安全不是 Parallel.ForEach 给的,是你自己要写的
Parallel.ForEach 本身是线程安全的——它不会崩,但它不管你的代码安不安全。你往里塞一个 sharedList.Add(item),大概率会抛 ArgumentException 或数据丢失。
- 常见错误现象:
Collection was modified; enumeration operation may not execute.或结果数量少于输入项数 - 正确做法:用线程安全集合,比如
ConcurrentBag、ConcurrentQueue,或加lock(但锁太重会抵消并行收益) - 特别注意:
List是单线程的,天然没这问题,但它也不是.ForEach Parallel.ForEach的替代品(类型受限、不支持异步)
性能不是“用了就快”,要看任务类型和数据量
小数据(比如 Parallel.ForEach 往往比 foreach 慢——线程创建、调度、同步开销压过了计算收益。
创想C2C商城系统,系统功能仿照淘宝设计,采用模块标签技术和静态html生成技术 基于Asp.Net/C#+SQL的开发的创想多用户商城系统,具有智能化、高扩展、稳定安全等特性,后台可自由添加频道,自由修改界面风格,商品无限级 分类,支持在线支付整合,通过安装和使用创想C2C商城系统,就可以轻松建立起专业大型的网上交易平台。创想C2C多用户商城系统5.6.3.8版本升级功能1.网站地区设置功能的增
- 适合加速的场景:
ProcessHeavy(item)类型任务(CPU 密集,单次 > 10ms),数据量 ≥ 数千 - 不适合的场景:IO 密集(如逐个 HTTP 调用)、短循环(
- .NET 6+ 推荐用
Parallel.ForEachAsync处理异步 IO,它比手动Task.WhenAll更可控(可设最大并发数、支持CancellationToken)
await Parallel.ForEachAsync(myList, new ParallelOptions { MaxDegreeOfParallelism = 10 }, async (item, token) =>
{
await CallApiAsync(item, token);
});
foreach + await 才是多数人真正该用的组合
别被“并行”二字带偏。90% 的业务逻辑需要顺序、可预测、易调试。比如“依次上传文件并记录日志”“按顺序更新数据库字段”,这时 foreach 配合 await 是最稳妥的选择。
- 它不抢资源、不争锁、异常堆栈清晰、断点好下
- 真要并发发请求?优先考虑
Task.WhenAll或上面提到的Parallel.ForEachAsync,而不是硬套Parallel.ForEach+async void - 记住:
list.ForEach(async item => await ...)是危险写法——编译器会转成async void,异常无法捕获,千万别用










