在 C# 的并行编程中,自定义分区器(Custom Partitioner)是一种高级但非常实用的技术,用于优化 Parallel.ForEach、PLINQ 等并行操作的数据分配策略。本文将带你从零开始,一步步理解什么是分区器、为什么需要自定义分区器,并通过完整示例演示如何实现一个高效的 C# 自定义分区器。
在 .NET 中,分区器负责将数据源划分为多个“块”(chunks),以便多个线程可以并行处理这些块。默认情况下,.NET 会使用内置的分区策略(如范围分区或块分区),但在某些场景下(例如数据大小不均、处理成本差异大),默认策略可能导致负载不均衡,从而影响性能。

考虑以下场景:
这时,使用 并行编程自定义分区器 就能显著提升程序效率。
我们以 OrderablePartitioner<T> 为基础类,实现一个按固定块大小划分的分区器。这个例子展示了如何创建一个支持动态负载的分区器。
using System;using System.Collections.Concurrent;using System.Collections.Generic;using System.Threading.Tasks;using System.Collections.Concurrent.Partitioners;public class ChunkPartitioner<T> : OrderablePartitioner<T>{ private readonly IList<T> _source; private readonly int _chunkSize; public ChunkPartitioner(IList<T> source, int chunkSize) : base(true, true, true) // keysOrderedInEachPartition, keysOrderedAcrossPartitions, dynamicPartitions { _source = source ?? throw new ArgumentNullException(nameof(source)); _chunkSize = chunkSize > 0 ? chunkSize : throw new ArgumentOutOfRangeException(nameof(chunkSize)); } public override IList<IEnumerator<KeyValuePair<long, T>>> GetOrderablePartitions(int partitionCount) { var partitions = new List<IEnumerator<KeyValuePair<long, T>>>(partitionCount); var position = 0L; for (int i = 0; i < partitionCount; i++) { partitions.Add(GetPartitionEnumerator(ref position)); } return partitions; } private IEnumerator<KeyValuePair<long, T>> GetPartitionEnumerator(ref long position) { while (true) { long startIndex, endIndex; lock (_source) { if (position >= _source.Count) yield break; startIndex = position; position += _chunkSize; endIndex = Math.Min(position, _source.Count); } for (long i = startIndex; i < endIndex; i++) { yield return new KeyValuePair<long, T>(i, _source[(int)i]); } } } public override bool SupportsDynamicPartitions => true; public override IEnumerable<KeyValuePair<long, T>> GetOrderableDynamicPartitions() { return GetOrderablePartitions(Environment.ProcessorCount); }}下面是一个使用上述 ChunkPartitioner 的完整示例:
class Program{ static void Main() { var data = Enumerable.Range(1, 1000).ToArray(); var partitioner = new ChunkPartitioner<int>(data, chunkSize: 50); Parallel.ForEach(partitioner, item => { // 模拟处理 Console.WriteLine($"Thread {Task.CurrentId}: 处理索引 {item.Key}, 值 {item.Value}"); Task.Delay(10).Wait(); // 模拟耗时操作 }); Console.WriteLine("完成!"); }}.NET 提供了 Partitioner.Create 方法来快速创建分区器,但它仅适用于简单场景。例如:
var defaultPartitioner = Partitioner.Create(data, loadBalance: true);Parallel.ForEach(defaultPartitioner, x => { /* 处理 */ });然而,当你需要更精细的控制(如自定义块大小、处理非列表数据源等),就必须实现自己的分区器。这也是 Partitioner.Create 自定义 所不能替代的高级用法。
ConcurrentQueue)chunkSize 对性能的影响keysOrderedInEachPartition = false 提升性能通过本文,你已经掌握了 C# 并行任务优化 中的关键技术——自定义分区器。它不仅能解决默认分区策略的局限性,还能显著提升多线程程序的吞吐量和响应速度。记住,合理使用 C# 自定义分区器 是迈向高性能并行编程的重要一步。
现在,你可以尝试在自己的项目中应用这一技术,观察性能变化,并不断调优!
本文由主机测评网于2025-12-17发表在主机测评网_免费VPS_免费云服务器_免费独立服务器,如有疑问,请联系我们。
本文链接:https://www.vpshk.cn/2025129269.html