概述 System.Threading.Tasks 命名空间提供 Parallel 类和 PLINQ(并行 LINQ),简化数据并行和任务并行的实现。它们自动将工作分配到多个线程。
Parallel.For 并行 for 循环,适合迭代次数已知的计算密集型任务。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 using System.Threading.Tasks;Parallel.For(0 , 100 , i => { Console.WriteLine($"索引 {i} ,线程: {Thread.CurrentThread.ManagedThreadId} " ); }); Parallel.For(0 , 1000 , new ParallelOptions { MaxDegreeOfParallelism = 4 }, i => { double result = Math.Sqrt(i) * Math.PI; });
线程局部变量(高性能) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 long sum = 0 ;Parallel.For(0 , 1000000 , () => 0L , (i, state, local) => { return local + i; }, local => Interlocked.Add(ref sum, local) ); Console.WriteLine($"总和: {sum} " );
Parallel.ForEach 并行遍历集合。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 var items = Enumerable.Range(1 , 100 ).ToList();Parallel.ForEach(items, item => { ProcessItem(item); }); int [] numbers = new int [1000 ];Parallel.ForEach(numbers, (num, state, index) => { numbers[index] = index * index; }); Parallel.ForEach(items, new ParallelOptions { MaxDegreeOfParallelism = 4 }, item => { Console.WriteLine($"{item} " ); });
提前退出(Break/Stop) 1 2 3 4 5 6 7 8 9 Parallel.For(0 , 1000000 , (i, state) => { if (i > 1000 ) { state.Break(); return ; } DoWork(i); });
Parallel.Invoke 并行执行多个操作。
1 2 3 4 5 6 7 8 9 10 11 12 Parallel.Invoke( () => DoWork1(), () => DoWork2(), () => DoWork3(), () => DownloadData() ); Parallel.Invoke(new ParallelOptions { MaxDegreeOfParallelism = 2 }, () => LongRunningTaskA(), () => LongRunningTaskB() );
完整示例:图像处理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 using System;using System.Drawing;using System.Threading.Tasks;class ImageProcessor { public static void ApplyGrayscale (Bitmap bitmap ) { Rectangle rect = new Rectangle(0 , 0 , bitmap.Width, bitmap.Height); System.Drawing.Imaging.BitmapData bmpData = bitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bitmap.PixelFormat); int bytesPerPixel = Image.GetPixelFormatSize(bitmap.PixelFormat) / 8 ; byte * ptr = (byte *)bmpData.Scan0; int stride = bmpData.Stride; Parallel.For(0 , bitmap.Height, y => { byte * row = ptr + (y * stride); for (int x = 0 ; x < bitmap.Width; x++) { int idx = x * bytesPerPixel; byte gray = (byte )(row[idx] * 0.299 + row[idx + 1 ] * 0.587 + row[idx + 2 ] * 0.114 ); row[idx] = gray; row[idx + 1 ] = gray; row[idx + 2 ] = gray; } }); bitmap.UnlockBits(bmpData); } }
PLINQ(并行 LINQ) 基础使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 using System.Linq;var numbers = Enumerable.Range(1 , 10000000 );var evenNumbers = numbers .AsParallel() .Where(n => n % 2 == 0 ) .ToList(); var sum = numbers.AsParallel().Sum();var average = numbers.AsParallel().Average();var result = numbers.AsParallel() .Aggregate( 0 , (local, n) => local + n, (total, local) => total + local, total => total );
执行顺序 1 2 3 4 5 6 7 8 9 var ordered = numbers.AsParallel().AsOrdered() .Where(x => x > 5000000 ) .ToList(); var unordered = numbers.AsParallel().AsUnordered() .Where(x => x > 5000000 ) .ToList();
控制并行度 1 2 3 4 5 6 7 8 9 10 11 var result = numbers.AsParallel() .WithDegreeOfParallelism(4 ) .WithExecutionMode(ParallelExecutionMode.ForceParallelism) .Where(n => IsPrime(n)) .ToList(); var sequential = numbers.AsParallel() .WithExecutionMode(ParallelExecutionMode.Default) .AsSequential() .Where(n => n % 2 == 0 );
合并选项 1 2 3 4 5 6 7 8 9 10 var results = numbers.AsParallel() .WithMergeOptions(ParallelMergeOptions.NotBuffered) .Select(x => HeavyCompute(x)) .ToList();
PLINQ 异常处理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 try { var results = Enumerable.Range(0 , 100 ) .AsParallel() .Select(x => 100 / x) .ToList(); } catch (AggregateException ae){ foreach (var ex in ae.InnerExceptions) { Console.WriteLine($"异常: {ex.Message} " ); } }
使用 CancellationToken 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 using System.Threading;CancellationTokenSource cts = new CancellationTokenSource(); cts.CancelAfter(1000 ); try { Parallel.For(0 , 10000000 , new ParallelOptions { CancellationToken = cts.Token }, i => { DoWork(i); }); } catch (OperationCanceledException){ Console.WriteLine("并行操作被取消" ); }
何时使用 Parallel/PLINQ
场景
推荐
CPU 密集型计算
✅ Parallel / PLINQ
迭代次数多(>1000)
✅ 值得并行化
简单循环体(少数指令)
❌ 并行开销大于收益
有依赖关系的迭代
❌ 必须顺序执行
IO 密集型操作
❌ 使用 async/await 代替
小数据量
❌ 顺序执行更快
性能注意事项 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 for (int i = 0 ; i < 1000000 ; i++){ sum += i; } Parallel.For(0 , 1000 , i => { var result = Enumerable.Range(0 , 1000000 ) .Select(x => Math.Sqrt(x) * Math.PI) .Sum(); }); Parallel.For(0 , 1000000 , () => 0 , (i, state, local) => local + i, local => Interlocked.Add(ref sum, local));
诊断与调试 1 2 3 4 5 6 7 8 9 var query = Enumerable.Range(0 , 100 ) .AsParallel() .WithDegreeOfParallelism(4 ) .Select(x => { Console.WriteLine($"处理 {x} ,线程: {Thread.CurrentThread.ManagedThreadId} " ); return x * 2 ; }) .ToList();
参考资源