c# Parallel.ForEach 和分区器(Partitioner)的结合使用
发布时间 - 2026-01-11 00:00:00 点击率:次Parallel.ForEach 默认采用动态分区策略,线程按需拉取小批量元素(8–64个);显式使用 Partitioner.Create 适用于需连续性、固定块大小、高效范围访问或降低协调开销的场景。
Parallel.ForEach 默认如何分区?
默认情况下,Parallel.ForEach 对 IEnumerable 使用的是「动态分区(dynamic partitioning)」策略:不是一次性把整个集合切分成固定几块,而是由线程在运行时按需从源中“拉取”小批量元素(比如 8–64 个),以减少争用和空闲等待。这种策略对大多数顺序可枚举场景够用,但对索引敏感、需局部缓存或 I/O 密集型操作,容易导致负载不均或重复开销。
什么时候必须显式传入 Partitioner.Create?
以下情况建议绕过默认行为,用 Partitioner.Create 显式控制分区逻辑:
- 源是数组或
IList,且每个分区需保持局部连续性(例如图像分块处理、矩阵行批处理) - 需要固定大小的块(如每次处理 1000 条记录,避免某线程只拿到 3 条)
- 底层数据源本身支持高效范围访问(如数据库游标、内存映射文件),但
IEnumerable包装后丢失了随机访问能力 - 想禁用动态分区带来的内部锁和协调开销(尤其在超低延迟场景)
典型写法是:Partitioner.Create(source, true) —— 第二个参数 true 表示启用静态分区(对数组 / 列表自动按索引切分),比默认动态方式更可预测。
Partitioner.Create 的三个重载怎么选?
关键看数据源类型和是否需要自定义逻辑:
-
Partitioner.Create(TSource[] source, bool loadBalance):最常用。数组 +loadBalance: false→ 每个线程分到连续大块;true→ 类似默认动态,但基于索引调度 -
Partitioner.Create(IEnumerable:仅当源本身已实现高效枚举(如自定义source) IEnumerator支持Reset或分段)才考虑,否则可能引发重复枚举或线程不安全 -
Partitioner.Create(int fromInclusive, int toExclusive, int rangeSize:纯索引区间分区,适合配合外部数据结构(如
)Span或数组下标计算),不依赖具体集合实例
错误用法示例:对非数组的 List 直接传 Partitioner.Create(list, true) —— 虽然能编译,但 true 参数在此无效,仍走动态路径;应先转成数组或用第三个重载。
分区器 + Parallel.ForEach 的实际性能陷阱
显式分区不等于性能提升,反而可能引入新问题:
- 分区粒度太粗(如 10 万条一个块):线程数少于 CPU 核心时严重浪费资源;某块耗时远超其他块时整体被拖慢
- 分区粒度太细(如每块 1 条):抵消并行收益,线程调度和锁开销反超计算收益
- 误用
Partitioner.Create(source, false)处理非数组源:触发NotSupportedException,因为只有数组和某些IList实现支持静态索引分区 - 在分区器内部做重量级初始化(如打开文件、建连接):每个分区执行一次,而非每个线程一次
var data = Enumerable.Range(0, 100000).ToArray();
// ✅ 推荐:固定块大小,每块 1000 项,静态切分
var partitioner = Partitioner.Create(0, data.Length, 1000);
Parallel.ForEach(partitioner, range => {
for (int i = range.Item1; i < range.Item2; i++) {
Process(data[i]);
}
});
真正难的是平衡「局部性」「负载均衡」「初始化成本」三者——多数项目卡在这一步,不是不会写,而是没测过不同 rangeSize 下的吞吐和 GC 行为。
# c#
# foreach
# bool
# int
# 数据结构
# 线程
# 数据库
# 负载均衡
# 切分
# 的是
# 自定义
# 按需
# 每块
# 小批量
# 在此
# 什么时候
# 是由
# 适用于
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
如何在 React 中条件性地遍历数组并渲染元素
百度浏览器网页无法复制文字怎么办 百度浏览器复制修复
JS弹性运动实现方法分析
Laravel如何实现数据导出到CSV文件_Laravel原生流式输出大数据量CSV【方案】
Laravel如何使用Socialite实现第三方登录?(微信/GitHub示例)
今日头条微视频如何找选题 今日头条微视频找选题技巧【指南】
Laravel Eloquent:优雅地将关联模型字段扁平化到主模型中
Laravel怎么连接多个数据库_Laravel多数据库连接配置
javascript中对象的定义、使用以及对象和原型链操作小结
Laravel如何获取当前登录用户信息_Laravel Auth门面使用与Session用户读取【技巧】
Laravel API资源(Resource)怎么用_格式化Laravel API响应的最佳实践
Laravel Octane如何提升性能_使用Laravel Octane加速你的应用
移动端手机网站制作软件,掌上时代,移动端网站的谷歌SEO该如何做?
Laravel如何实现图片防盗链功能_Laravel中间件验证Referer来源请求【方案】
如何用手机制作网站和网页,手机移动端的网站能制作成中英双语的吗?
如何获取PHP WAP自助建站系统源码?
Laravel队列由Redis驱动怎么配置_Laravel Redis队列使用教程
Laravel如何安装Breeze扩展包_Laravel用户注册登录功能快速实现【流程】
详解jQuery停止动画——stop()方法的使用
猎豹浏览器开发者工具怎么打开 猎豹浏览器F12调试工具使用【前端必备】
如何用腾讯建站主机快速创建免费网站?
如何用y主机助手快速搭建网站?
如何在 Python 中将列表项按字母顺序编号(a.、b.、c. …)
微信小程序 canvas开发实例及注意事项
网站设计制作书签怎么做,怎样将网页添加到书签/主页书签/桌面?
Laravel如何集成微信支付SDK_Laravel使用yansongda-pay实现扫码支付【实战】
浅谈redis在项目中的应用
Win11任务栏卡死怎么办 Windows11任务栏无反应解决方法【教程】
高端企业智能建站程序:SEO优化与响应式模板定制开发
Laravel怎么进行数据库事务处理_Laravel DB Facade事务操作确保数据一致性
Laravel怎么清理缓存_Laravel optimize clear命令详解
详解jQuery中的事件
简单实现Android文件上传
Laravel如何操作JSON类型的数据库字段?(Eloquent示例)
活动邀请函制作网站有哪些,活动邀请函文案?
javascript日期怎么处理_如何格式化输出
Laravel怎么进行数据库回滚_Laravel Migration数据库版本控制与回滚操作
JavaScript如何实现继承_有哪些常用方法
详解免费开源的DotNet二维码操作组件ThoughtWorks.QRCode(.NET组件介绍之四)
Laravel怎么配置自定义表前缀_Laravel数据库迁移与Eloquent表名映射【步骤】
如何在橙子建站上传落地页?操作指南详解
uc浏览器二维码扫描入口_uc浏览器扫码功能使用地址
Laravel API路由如何设计_Laravel构建RESTful API的路由最佳实践
高端智能建站公司优选:品牌定制与SEO优化一站式服务
Python文件流缓冲机制_IO性能解析【教程】
Win11应用商店下载慢怎么办 Win11更改DNS提速下载【修复】
Laravel怎么实现前端Toast弹窗提示_Laravel Session闪存数据Flash传递给前端【方法】
HTML5空格在Angular项目里怎么处理_Angular中空格的渲染问题【详解】
微信推文制作网站有哪些,怎么做微信推文,急?
HTML透明颜色代码在Angular里怎么设置_Angular透明颜色使用指南【详解】


)