多线程之并行循环(Parallel.For、Parallel.ForEach)

并行循环原理与实践

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、总结

并行循环的本质:

  • 数据并行性的自动化实现

  • 基于工作窃取算法实现动态负载均衡

  • 使用范围分割和块分割策略分配工作

  • 内置异常聚合和状态管理机制

核心优势:

  1. 自动并行化:自动将循环迭代分配到多个线程

  2. 负载均衡:动态调整工作分配,避免线程空闲

  3. 简单易用:与标准循环相似的语法

  4. 性能优化:自动选择最优的分区策略

适用场景

  • 计算密集型循环:数学计算、图像处理

  • 数据并行处理:集合转换、数据验证

  • 独立迭代:迭代之间没有依赖关系

  • 足够工作量:循环体有足够的工作量来抵消并行开销

使用要点:

  • 确保迭代之间是独立的

  • 使用线程安全的数据结构或线程局部变量

  • 合理设置最大并行度

  • 避免在循环体中进行同步 I/O 操作

  • 妥善处理异常和循环控制

并行循环是处理数据并行任务的有力工具,在合适的场景下可以显著提升程序性能!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值