parallel.foreach 比 foreach 快因自动并行化,但短任务反慢于线程开销;需用 interlocked、concurrent 集合或细粒度 lock 保障共享变量安全;注意 aggregateexception 需展开处理。
Parallel.ForEach 为什么比 foreach 快,但有时反而更慢?
因为 Parallel.ForEach 会自动拆分数据、分配线程、合并结果,省去手动管理 Task 的开销;但若迭代体执行时间极短(比如只做一次 i++),线程调度和同步的开销会远超计算收益。
- 适合场景:每个迭代项耗时 ≥ 几毫秒,且无强顺序依赖(如批量文件处理、HTTP 请求、图像像素计算)
- 不适用场景:循环体仅含简单算术、或需严格按索引顺序写入同一数组/集合
- 注意默认线程数受
ThreadPool限制,高并发小任务建议用ParallelOptions.MaxDegreeOfParallelism控制
如何安全地在 Parallel.ForEach 中更新共享变量?
直接读写普通变量(如 int count = 0)会导致竞态——多个线程同时执行 count++ 可能只加 1 次。必须用线程安全方式:
- 用
Interlocked.Increment(ref count)替代count++(整数类计数首选) - 对集合操作,改用线程安全类型:如
ConcurrentBag<t></t>、ConcurrentQueue<t></t>,而非List<t></t> - 若逻辑复杂,用
lock(obj)包裹临界区,但粒度要小,避免锁住整个循环体
Parallel.For 和 Parallel.ForEach 的关键参数差异
两者都支持 ParallelOptions,但循环结构不同导致行为差异明显: