文章目录
1、从生活比喻开始
场景:工厂生产线
-
传统 for 循环:像单个工人从头到尾处理所有产品
-
Parallel.For:像多个工人平均分配产品编号范围
-
工人A:处理产品 1-100
-
工人B:处理产品 101-200
-
工人C:处理产品 201-300
-
-
Parallel.ForEach:像多个工人从共享队列中取产品处理
-
所有产品放在一个传送带上
-
每个工人从传送带拿一个产品处理
-
处理完再拿下一个
-
并行循环的本质:将循环迭代自动分割成多个块,分配给多个线程并行执行。
2、并行循环的核心本质
2.1 工作分割策略
// 并行循环内部的工作分割概念
class ParallelPartitioning
{
// 1. 范围分割 (Range Partitioning) - 用于 Parallel.For
class RangePartitioner
{
public IEnumerable<Tuple<int, int>> PartitionRange(int from, int to, int partitionCount)
{
int totalItems = to - from;
int baseSize = totalItems / partitionCount;
int remainder = totalItems % partitionCount;
int start = from;
for (int i = 0; i < partitionCount; i++)
{
int end = start + baseSize + (i < remainder ? 1 : 0);
yield return Tuple.Create(start, end);
start = end;
}
}
}
// 2. 块分割 (Chunk Partitioning) - 用于 Parallel.ForEach
class ChunkPartitioner
{
public IEnumerable<List<T>> PartitionCollection<T>(IEnumerable<T> source, int partitionCount)
{
var partitions = new List<List<T>>(partitionCount);
for (int i = 0; i < partitionCount; i++)
{
partitions.Add(new List<T>());
}
int currentPartition = 0;
foreach (var item in source)
{
partitions[currentPartition].Add(item);
currentPartition = (currentPartition + 1) % partitionCount;
}
return partitions;
}
}
// 3. 动态负载均衡 - 工作窃取 (Work Stealing)
class WorkStealingQueue
{
private ConcurrentQueue<WorkItem>[] _workerQueues;
public void BalanceLoad()
{
// 如果某个线程完成了自己的工作,可以从其他线程"窃取"工作
foreach (var queue in _workerQueues)
{
if (queue.TryDequeue(out WorkItem work))
{
ExecuteWork(work);
}
}
}
}
}
2.2 并行循环状态机
class ParallelLoopStateInternal
{
// 并行循环的内部状态管理
class ParallelLoopState
{
volatile bool _shouldExit = false;
volatile bool _shouldBreak = false;
long _lowestBreakIteration = long.MaxValue;
public void Break()
{
_shouldBreak = true;
// 记录最早请求Break的迭代
// 保证所有更低索引的迭代都会执行
}
public void Stop()
{
_shouldExit = true;
// 尽快退出,不保证执行顺序
}
public bool ShouldExitCurrentIteration
{
get { return _shouldExit || (_shouldBreak && CurrentIteration > _lowestBreakIteration); }
}
}
}
3、底层原理深入解析
3.1 并行循环的执行流程
class ParallelForExecutionFlow
{
public static ParallelLoopResult For(int fromInclusive, int toExclusive, Action<int> body)
{
// 1. 计算迭代总数和分区策略
int totalIterations = toExclusive - fromInclusive;
int degreeOfParallelism = DetermineOptimalDegreeOfParallelism(totalIterations);
// 2. 创建工作项和状态跟踪
var loopResult = new ParallelLoopResult();
var loopState = new ParallelLoopState();
// 3. 分割工作范围
var partitions = CreatePartitions(fromInclusive, toExclusive, degreeOfParallelism);
// 4. 启动并行任务
var tasks = new Task[partitions.Count];
for (int i = 0; i < partitions.Count; i++)
{
var partition = partitions[i];
tasks[i] = Task.Run(() => ProcessPartition(partition, body, loopState, loopResult));
}
// 5. 等待所有任务完成并聚合结果
Task.WaitAll(tasks);
return loopResult;
}
private static void ProcessPartition(Tuple<int, int> range, Action<int> body,
ParallelLoopState state, ParallelLoopResult result)
{
try
{
for (int i = range.Item1; i < range.Item2; i++)
{
// 检查是否应该提前退出
if (state.ShouldExitCurrentIteration)
break;
// 执行循环体
body(i);
// 处理异常等情况
}
}
catch (Exception ex)
{
// 记录异常
result.AddException(ex);
state.Stop();
}
}
}
3.2 负载均衡机制
class LoadBalancingMechanism
{
// 工作窃取算法的简化实现
class WorkStealingScheduler
{
private ConcurrentQueue<WorkChunk>[] _workerQueues;
private int _totalWorkers;
public void ExecuteParallelFor(int start, int end, Action<int> body)
{
// 初始范围分割
var initialChunks = CreateInitialChunks(start, end, _totalWorkers);
// 为每个工作线程分配初始工作
for (int i = 0; i < _totalWorkers; i++)
{
int workerId = i;
Task.Run(() => WorkerLoop(workerId, initialChunks[workerId], body));
}
}
private void WorkerLoop(int workerId, WorkChunk initialChunk, Action<int> body)
{
var localWork = new Stack<WorkChunk>();
localWork.Push(initialChunk);
while (localWork.Count > 0 || TryStealWork(workerId, out WorkChunk stolenChunk))
{
WorkChunk currentChunk;
if (localWork.Count > 0)
{
currentChunk = localWork.Pop();
}
else
{
currentChunk = stolenChunk;
}
// 处理当前块
ProcessWorkChunk(currentChunk, body, localWork);
}
}
private bool TryStealWork(int thiefWorkerId, out WorkChunk chunk)
{
// 随机选择受害者线程尝试窃取工作
var random = new Random();
for (int i = 0; i < _totalWorkers; i++)
{
int victimId = (thiefWorkerId + i) % _totalWorkers;
if (victimId != thiefWorkerId &&
_workerQueues[victimId].TryDequeue(out chunk))
{
return true;
}
}
chunk = null;
return false;
}
}
}
4、并行循环的完整使用
4.1 基础并行循环
class BasicParallelLoops
{
public void DemonstrateBasicParallelFor()
{
Console.WriteLine("=== Parallel.For 基础演示 ===\n");
int totalIterations = 20;
// 1. 基本 Parallel.For
Console.WriteLine("1. 基本 Parallel.For:");
Parallel.For(0, totalIterations, i => {
Console.WriteLine($"迭代 {i} 在线程 {Thread.CurrentThread.ManagedThreadId} 上执行");
Thread.Sleep(100); // 模拟工作
});
// 2. 带线程局部数据的 Parallel.For
Console.WriteLine("\n2. 带线程局部数据的 Parallel.For:");
long totalSum = 0;
Parallel.For(0, totalIterations,
() => 0L, // 初始化线程局部状态
(i, loopState, localSum) => {
// 每个线程维护自己的局部和
localSum += i;
Console.WriteLine($"线程 {Thread.CurrentThread.ManagedThreadId} 处理 {i}, 局部和: {localSum}");
Thread.Sleep(50);
return localSum;
},
localSum => {
// 合并所有线程的局部和
Interlocked.Add(ref totalSum, localSum);
Console.WriteLine($"线程 {Thread.CurrentThread.ManagedThreadId} 完成,贡献: {localSum}");
}
);
Console.WriteLine($"\n最终总和: {totalSum}");
// 3. 验证结果正确性
long expectedSum = Enumerable.Range(0, totalIterations).Sum();
Console.WriteLine($"期望总和: {expectedSum}");
Console.WriteLine($"结果正确: {totalSum == expectedSum}");
}
public void DemonstrateBasicParallelForEach()
{
Console.WriteLine("\n=== Parallel.ForEach 基础演示 ===\n");
var data = new List<string>
{
"苹果", "香蕉", "橙子", "葡萄", "芒果",
"菠萝", "草莓", "西瓜", "桃子", "梨子"
};
// 1. 基本 Parallel.ForEach
Console.WriteLine("1. 基本 Parallel.ForEach:");
Parallel.ForEach(data, fruit => {
Console.WriteLine($"处理 '{fruit}' 在线程 {Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(200); // 模拟处理时间
});
// 2. 带线程局部数据的 Parallel.ForEach
Console.WriteLine("\n2. 带线程局部数据的 Parallel.ForEach:");
var processedFruits = new ConcurrentBag<string>();
Parallel.ForEach(data,
() => new List<string>(), // 初始化线程局部列表
(fruit, loopState, localList) => {
string processed = $"{fruit}_已处理";
localList.Add(processed);
Console.WriteLine($"线程 {Thread.CurrentThread.ManagedThreadId} 处理: {fruit} -> {processed}");
Thread.Sleep(100);
return localList;
},
localList => {
// 合并线程局部结果
foreach (var item in localList)
{
processedFruits.Add(item);
}
Console.WriteLine($"线程 {Thread.CurrentThread.ManagedThreadId} 完成,处理了 {localList.Count} 个项目");
}
);
Console.WriteLine($"\n总共处理了 {processedFruits.Count} 个水果:");
foreach (var fruit in processedFruits)
{
Console.WriteLine($" - {fruit}");
}
}
}
4.2 高级控制和配置
class AdvancedParallelControl
{
public void DemonstrateParallelOptions()
{
Console.WriteLine("=== 并行选项和高级控制 ===\n");
// 1. 配置并行度
var optionsWithMaxDOP = new ParallelOptions
{
MaxDegreeOfParallelism = 2 // 最多使用2个线程
};
Console.WriteLine("1. 限制最大并行度为2:");
Parallel.For(0, 10, optionsWithMaxDOP, i => {
Console.WriteLine($"迭代 {i} 在线程 {Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(500);
});
// 2. 使用取消令牌
var cts = new CancellationTokenSource();
var optionsWithCancellation = new ParallelOptions
{
CancellationToken = cts.Token,
MaxDegreeOfParallelism = Environment.ProcessorCount
};
Console.WriteLine("\n2. 带取消功能的并行循环:");
Task.Run(() => {
try
{
Parallel.For(0, 100, optionsWithCancellation, i => {
// 检查取消请求
optionsWithCancellation.CancellationToken.ThrowIfCancellationRequested();
Console.WriteLine($"处理 {i}");
Thread.Sleep(100);
if (i == 25)
{
Console.WriteLine("在迭代25时请求取消");
cts.Cancel();
}
});
}
catch (OperationCanceledException)
{
Console.WriteLine("并行循环被取消");
}
});
Thread.Sleep(3000); // 给任务一些执行时间
// 3. 使用 ParallelLoopState 控制循环
Console.WriteLine("\n3. 使用 ParallelLoopState 控制循环:");
var result = Parallel.For(0, 50, (i, loopState) => {
if (i >= 20)
{
Console.WriteLine($"迭代 {i} 请求停止");
loopState.Stop(); // 尽快停止
return;
}
Console.WriteLine($"处理迭代 {i}");
Thread.Sleep(50);
});
Console.WriteLine($"循环完成: IsCompleted = {result.IsCompleted}, LowestBreakIteration = {result.LowestBreakIteration}");
// 4. 使用 Break 和 Stop 的区别
Console.WriteLine("\n4. Break 和 Stop 的区别演示:");
Console.WriteLine("使用 Break():");
var breakResult = Parallel.For(0, 100, (i, loopState) => {
if (i == 50)
{
Console.WriteLine($"迭代 {i} 调用 Break()");
loopState.Break();
}
if (loopState.ShouldExitCurrentIteration)
{
Console.WriteLine($"迭代 {i} 应该退出");
return;
}
Console.WriteLine($"处理迭代 {i}");
});
Console.WriteLine($"Break 结果 - 完成: {breakResult.IsCompleted}, 最低中断迭代: {breakResult.LowestBreakIteration}");
Console.WriteLine("\n使用 Stop():");
var stopResult = Parallel.For(0, 100, (i, loopState) => {
if (i == 50)
{
Console.WriteLine($"迭代 {i} 调用 Stop()");
loopState.Stop();
}
if (loopState.IsStopped)
{
return;
}
Console.WriteLine($"处理迭代 {i}");
});
Console.WriteLine($"Stop 结果 - 完成: {stopResult.IsCompleted}, 是否停止: {stopResult.IsCompleted}");
}
}
4.3 异常处理和聚合
class ParallelExceptionHandling
{
public void DemonstrateExceptionHandling()
{
Console.WriteLine("=== 并行循环异常处理 ===\n");
// 1. 基本的异常处理
Console.WriteLine("1. 基本的异常处理:");
try
{
Parallel.For(0, 20, i => {
if (i % 7 == 0) // 在特定迭代抛出异常
{
throw new InvalidOperationException($"迭代 {i} 发生错误");
}
Console.WriteLine($"成功处理迭代 {i}");
Thread.Sleep(50);
});
}
catch (AggregateException ae)
{
Console.WriteLine($"捕获到 {ae.InnerExceptions.Count} 个异常:");
foreach (var ex in ae.InnerExceptions)
{
Console.WriteLine($" - {ex.Message}");
}
}
// 2. 在循环内部处理异常(避免停止整个循环)
Console.WriteLine("\n2. 在循环内部处理异常:");
var exceptions = new ConcurrentQueue<Exception>();
Parallel.For(0, 30, i => {
try
{
if (i % 5 == 0)
{
throw new ArgumentException($"参数错误在迭代 {i}");
}
if (i % 8 == 0)
{
throw new InvalidOperationException($"操作错误在迭代 {i}");
}
Console.WriteLine($"成功处理迭代 {i}");
Thread.Sleep(30);
}
catch (Exception ex)
{
exceptions.Enqueue(ex);
Console.WriteLine($"在迭代 {i} 中捕获异常: {ex.GetType().Name} - {ex.Message}");
}
});
Console.WriteLine($"\n总共捕获 {exceptions.Count} 个异常");
// 3. 使用 ParallelLoopResult 检查状态
Console.WriteLine("\n3. 使用 ParallelLoopResult 检查状态:");
ParallelLoopResult loopResult = default;
try
{
loopResult = Parallel.For(0, 10, (i, state) => {
if (i == 5)
{
throw new Exception("测试异常");
}
Console.WriteLine($"处理迭代 {i}");
});
}
catch (AggregateException)
{
Console.WriteLine("发生异常,但循环可能部分完成");
}
Console.WriteLine($"循环状态 - 完成: {loopResult.IsCompleted}, 最低中断迭代: {loopResult.LowestBreakIteration}");
}
}
4.4 性能优化和最佳实践
class ParallelPerformanceOptimization
{
private Stopwatch _stopwatch = new Stopwatch();
public void DemonstratePerformanceComparison()
{
Console.WriteLine("=== 性能比较和优化 ===\n");
int dataSize = 1000000;
var data = Enumerable.Range(0, dataSize).ToArray();
var results = new double[dataSize];
// 1. 顺序 for 循环
_stopwatch.Restart();
for (int i = 0; i < data.Length; i++)
{
results[i] = PerformCalculation(data[i]);
}
_stopwatch.Stop();
Console.WriteLine($"顺序 for 循环: {_stopwatch.ElapsedMilliseconds} ms");
// 2. 并行 for 循环
_stopwatch.Restart();
Parallel.For(0, data.Length, i => {
results[i] = PerformCalculation(data[i]);
});
_stopwatch.Stop();
Console.WriteLine($"并行 for 循环: {_stopwatch.ElapsedMilliseconds} ms");
// 3. 使用分区器优化
_stopwatch.Restart();
var partitioner = Partitioner.Create(0, data.Length);
Parallel.ForEach(partitioner, range => {
for (int i = range.Item1; i < range.Item2; i++)
{
results[i] = PerformCalculation(data[i]);
}
});
_stopwatch.Stop();
Console.WriteLine($"使用分区器的并行循环: {_stopwatch.ElapsedMilliseconds} ms");
// 4. 不同并行度的性能比较
Console.WriteLine("\n不同并行度的性能比较:");
int[] degreesOfParallelism = { 1, 2, 4, 8, Environment.ProcessorCount };
foreach (int dop in degreesOfParallelism)
{
_stopwatch.Restart();
var options = new ParallelOptions { MaxDegreeOfParallelism = dop };
Parallel.For(0, data.Length, options, i => {
results[i] = PerformCalculation(data[i]);
});
_stopwatch.Stop();
Console.WriteLine($"并行度 {dop}: {_stopwatch.ElapsedMilliseconds} ms");
}
}
public void DemonstrateWhenToUseParallel()
{
Console.WriteLine("\n=== 何时使用并行循环 ===\n");
// 1. 适合并行的情况:计算密集型工作
Console.WriteLine("1. 计算密集型工作 - 适合并行:");
var computeIntensiveData = Enumerable.Range(0, 1000).ToArray();
_stopwatch.Restart();
Parallel.ForEach(computeIntensiveData, item => {
// 模拟计算密集型工作
for (int j = 0; j < 10000; j++)
{
Math.Sqrt(item + j);
}
});
_stopwatch.Stop();
Console.WriteLine($"计算密集型并行处理: {_stopwatch.ElapsedMilliseconds} ms");
// 2. 不适合并行的情况:小数据量或简单操作
Console.WriteLine("\n2. 小数据量简单操作 - 可能不适合并行:");
var smallData = Enumerable.Range(0, 100).ToArray();
_stopwatch.Restart();
for (int i = 0; i < smallData.Length; i++)
{
// 简单操作
var result = smallData[i] * 2;
}
_stopwatch.Stop();
Console.WriteLine($"小数据顺序处理: {_stopwatch.ElapsedMilliseconds} ms");
_stopwatch.Restart();
Parallel.ForEach(smallData, item => {
var result = item * 2;
});
_stopwatch.Stop();
Console.WriteLine($"小数据并行处理: {_stopwatch.ElapsedMilliseconds} ms");
// 3. I/O 密集型工作
Console.WriteLine("\n3. I/O 密集型工作 - 需要特殊处理:");
var urls = new[] { "http://example.com", "http://example.org", "http://example.net" };
// 错误方式:在并行循环中直接进行同步 I/O
_stopwatch.Restart();
try
{
Parallel.ForEach(urls, url => {
using (var client = new System.Net.WebClient())
{
string content = client.DownloadString(url); // 同步 I/O,阻塞线程
Console.WriteLine($"下载 {url} 完成,长度: {content.Length}");
}
});
}
catch (Exception ex)
{
Console.WriteLine($"错误: {ex.Message}");
}
_stopwatch.Stop();
Console.WriteLine($"同步 I/O 并行处理: {_stopwatch.ElapsedMilliseconds} ms");
// 正确方式:使用异步方法
Console.WriteLine("\n正确方式 - 使用异步方法:");
_stopwatch.Restart();
var asyncTasks = urls.Select(async url => {
using (var client = new System.Net.WebClient())
{
string content = await client.DownloadStringTaskAsync(url);
Console.WriteLine($"异步下载 {url} 完成,长度: {content.Length}");
}
}).ToArray();
Task.WaitAll(asyncTasks);
_stopwatch.Stop();
Console.WriteLine($"异步 I/O 处理: {_stopwatch.ElapsedMilliseconds} ms");
}
private double PerformCalculation(int input)
{
// 模拟一些计算工作
double result = 0;
for (int i = 0; i < 100; i++)
{
result += Math.Sqrt(input + i) * Math.Sin(input);
}
return result;
}
}
4.5 自定义分区器和高级模式
class CustomPartitioners
{
public void DemonstrateCustomPartitioning()
{
Console.WriteLine("=== 自定义分区器 ===\n");
var data = Enumerable.Range(0, 100).ToArray();
// 1. 使用内置分区器
Console.WriteLine("1. 使用内置分区器:");
var rangePartitioner = Partitioner.Create(0, data.Length, 10); // 块大小10
Parallel.ForEach(rangePartitioner, range => {
Console.WriteLine($"线程 {Thread.CurrentThread.ManagedThreadId} 处理范围 [{range.Item1}-{range.Item2})");
for (int i = range.Item1; i < range.Item2; i++)
{
// 处理数据
}
Thread.Sleep(100);
});
// 2. 自定义负载均衡分区器
Console.WriteLine("\n2. 自定义负载均衡分区器:");
var loadBalancingPartitioner = new LoadBalancingPartitioner<int>(data);
Parallel.ForEach(loadBalancingPartitioner, item => {
Console.WriteLine($"线程 {Thread.CurrentThread.ManagedThreadId} 处理项目 {item}");
Thread.Sleep(50);
});
// 3. 基于数据特性的分区
Console.WriteLine("\n3. 基于数据特性的分区:");
var complexData = GenerateComplexData(100);
var customPartitioner = new ComplexityBasedPartitioner(complexData);
Parallel.ForEach(customPartitioner, chunk => {
Console.WriteLine($"线程 {Thread.CurrentThread.ManagedThreadId} 处理复杂数据块,大小: {chunk.Length}");
foreach (var item in chunk)
{
ProcessComplexItem(item);
}
});
}
// 自定义负载均衡分区器
public class LoadBalancingPartitioner<T> : Partitioner<T>
{
private readonly IList<T> _data;
public LoadBalancingPartitioner(IList<T> data)
{
_data = data;
}
public override IList<IEnumerator<T>> GetPartitions(int partitionCount)
{
var partitions = new List<IEnumerator<T>>(partitionCount);
for (int i = 0; i < partitionCount; i++)
{
partitions.Add(GetEnumeratorForPartition(i, partitionCount));
}
return partitions;
}
private IEnumerator<T> GetEnumeratorForPartition(int partitionIndex, int totalPartitions)
{
// 简单的轮询分配策略
for (int i = partitionIndex; i < _data.Count; i += totalPartitions)
{
yield return _data[i];
}
}
}
// 基于复杂度的分区器
public class ComplexityBasedPartitioner : Partitioner<ComplexData[]>
{
private readonly List<ComplexData> _data;
private readonly int _desiredChunkSize;
public ComplexityBasedPartitioner(List<ComplexData> data, int desiredChunkSize = 5)
{
_data = data;
_desiredChunkSize = desiredChunkSize;
}
public override IList<IEnumerator<ComplexData[]>> GetPartitions(int partitionCount)
{
var partitions = new List<IEnumerator<ComplexData[]>>();
// 根据数据复杂度创建不同大小的块
var chunks = CreateComplexityBasedChunks();
foreach (var chunk in chunks)
{
partitions.Add(new List<ComplexData[]> { chunk }.GetEnumerator());
}
return partitions;
}
private List<ComplexData[]> CreateComplexityBasedChunks()
{
var chunks = new List<ComplexData[]>();
var currentChunk = new List<ComplexData>();
int currentComplexity = 0;
foreach (var item in _data.OrderByDescending(x => x.Complexity))
{
if (currentChunk.Count >= _desiredChunkSize ||
currentComplexity + item.Complexity > 100) // 复杂度阈值
{
if (currentChunk.Count > 0)
{
chunks.Add(currentChunk.ToArray());
currentChunk = new List<ComplexData>();
currentComplexity = 0;
}
}
currentChunk.Add(item);
currentComplexity += item.Complexity;
}
if (currentChunk.Count > 0)
{
chunks.Add(currentChunk.ToArray());
}
return chunks;
}
}
private List<ComplexData> GenerateComplexData(int count)
{
var random = new Random();
return Enumerable.Range(0, count)
.Select(i => new ComplexData
{
Id = i,
Complexity = random.Next(1, 20)
})
.ToList();
}
private void ProcessComplexItem(ComplexData item)
{
// 模拟处理时间与复杂度相关
Thread.Sleep(item.Complexity * 10);
}
}
public class ComplexData
{
public int Id { get; set; }
public int Complexity { get; set; } // 1-20, 数值越大处理时间越长
}
5、并行循环的内部工作机制
5.1 动态负载均衡
class DynamicLoadBalancing
{
// 工作窃取队列的简化实现
class WorkStealingQueue<T>
{
private readonly ConcurrentQueue<WorkChunk<T>>[] _workerQueues;
private readonly int _workerCount;
public WorkStealingQueue(int workerCount)
{
_workerCount = workerCount;
_workerQueues = new ConcurrentQueue<WorkChunk<T>>[workerCount];
for (int i = 0; i < workerCount; i++)
{
_workerQueues[i] = new ConcurrentQueue<WorkChunk<T>>();
}
}
public void AddWork(int workerId, WorkChunk<T> chunk)
{
_workerQueues[workerId].Enqueue(chunk);
}
public bool TryGetWork(int workerId, out WorkChunk<T> chunk)
{
// 首先尝试从自己的队列获取工作
if (_workerQueues[workerId].TryDequeue(out chunk))
{
return true;
}
// 如果自己的队列为空,尝试从其他队列窃取工作
for (int i = 0; i < _workerCount; i++)
{
int victimId = (workerId + i) % _workerCount;
if (victimId != workerId && _workerQueues[victimId].TryDequeue(out chunk))
{
return true;
}
}
chunk = default;
return false;
}
}
public class WorkChunk<T>
{
public int Start { get; set; }
public int End { get; set; }
public T[] Data { get; set; }
}
}
6、最佳实践和注意事项
6.1 正确模式
class ParallelLoopBestPractices
{
public void GoodPatterns()
{
// 1. 使用线程安全的数据结构
var results = new ConcurrentBag<int>();
var sourceData = Enumerable.Range(0, 1000).ToArray();
Parallel.ForEach(sourceData, item => {
int result = ProcessItem(item);
results.Add(result); // 线程安全
});
// 2. 使用线程局部变量减少锁竞争
long total = 0;
Parallel.For(0, 1000,
() => 0L, // 初始化局部状态
(i, loopState, localSum) => {
localSum += ProcessItem(i);
return localSum;
},
localSum => {
Interlocked.Add(ref total, localSum); // 只在合并时使用原子操作
}
);
// 3. 合理设置并行度
var options = new ParallelOptions {
MaxDegreeOfParallelism = Environment.ProcessorCount // 根据CPU核心数设置
};
Parallel.For(0, 1000, options, i => {
// 工作
});
// 4. 避免在并行循环中修改共享状态
var sharedCounter = 0;
Parallel.For(0, 1000, i => {
// 错误:直接修改共享状态
// sharedCounter++;
// 正确:使用线程安全的方式
Interlocked.Increment(ref sharedCounter);
});
}
public void WhenNotToUseParallelLoops()
{
// 1. 循环体非常简单时
var simpleData = Enumerable.Range(0, 100).ToArray();
// 可能比顺序循环更慢
Parallel.ForEach(simpleData, item => {
var result = item * 2; // 非常简单的工作
});
// 2. 迭代之间有依赖关系时
var dependentData = new int[100];
for (int i = 1; i < dependentData.Length; i++)
{
// 每个迭代依赖前一个迭代的结果
dependentData[i] = dependentData[i - 1] + i;
}
// 不能并行化!
// Parallel.For(1, dependentData.Length, i => {
// dependentData[i] = dependentData[i - 1] + i; // 数据竞争!
// });
// 3. 需要保证顺序时
var orderedData = new List<string>();
var source = Enumerable.Range(0, 100);
// 顺序很重要时不要使用并行循环
foreach (var item in source)
{
orderedData.Add($"Item_{item}"); // 保证顺序
}
}
private int ProcessItem(int item)
{
// 模拟一些工作
Thread.Sleep(1);
return item * item;
}
}
7、总结
并行循环的本质:
-
是数据并行性的自动化实现
-
基于工作窃取算法实现动态负载均衡
-
使用范围分割和块分割策略分配工作
-
内置异常聚合和状态管理机制
核心优势:
-
自动并行化:自动将循环迭代分配到多个线程
-
负载均衡:动态调整工作分配,避免线程空闲
-
简单易用:与标准循环相似的语法
-
性能优化:自动选择最优的分区策略
适用场景:
-
计算密集型循环:数学计算、图像处理
-
数据并行处理:集合转换、数据验证
-
独立迭代:迭代之间没有依赖关系
-
足够工作量:循环体有足够的工作量来抵消并行开销
使用要点:
-
确保迭代之间是独立的
-
使用线程安全的数据结构或线程局部变量
-
合理设置最大并行度
-
避免在循环体中进行同步 I/O 操作
-
妥善处理异常和循环控制
并行循环是处理数据并行任务的有力工具,在合适的场景下可以显著提升程序性能!
并行循环原理与实践
1185

被折叠的 条评论
为什么被折叠?



