1 using System; 2 using System.Collections.Concurrent; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Threading; 6 using System.Threading.Tasks; 7 8 namespace Try 9 { 10 public class ParallelTest 11 { 12 #region 分区块并行执行 13 public static void TestPartition() 14 { 15 var datas = Enumerable.Range(0, 100000).ToList(); 16 PartitionByPartCount(datas,5); 17 PartitionByPartSize(datas,100); 18 } 19 20 private static void PartitionByPartCount<T>(IList<T> datas, int partCount) 21 { 22 var partSize = (int)Math.Ceiling(datas.Count / (double)partCount); 23 var partitioner = Partitioner.Create(0, datas.Count, partSize); 24 Parallel.ForEach(partitioner, (part, state, partIndex) => { 25 for (int index = part.Item1; index < part.Item2; index++) 26 { 27 Console.WriteLine($"partIndex:{partIndex},index:{index},data:{datas[index]}"); 28 } 29 }); 30 } 31 32 private static void PartitionByPartSize<T>(IList<T> datas, int partSize) 33 { 34 var partitioner = Partitioner.Create(0, datas.Count, partSize); 35 Parallel.ForEach(partitioner, (part, state, partIndex) => { 36 for (int index = part.Item1; index < part.Item2; index++) 37 { 38 Console.WriteLine($"partIndex:{partIndex},index:{index},data:{datas[index]}"); 39 } 40 }); 41 } 42 #endregion 43 44 #region 取消Parallel 45 public static void TestCancel() 46 { 47 int[] nums = Enumerable.Range(0, 10000000).ToArray(); 48 CancellationTokenSource cts = new CancellationTokenSource(); 49 50 // Use ParallelOptions instance to store the CancellationToken 51 ParallelOptions po = new ParallelOptions(); 52 po.CancellationToken = cts.Token; 53 po.MaxDegreeOfParallelism = System.Environment.ProcessorCount; 54 Console.WriteLine("Press any key to start. Press 'c' to cancel."); 55 Console.ReadKey(); 56 57 // Run a task so that we can cancel from another thread. 58 Task.Factory.StartNew(() => 59 { 60 if (Console.ReadKey().KeyChar == 'c') 61 cts.Cancel(); 62 Console.WriteLine("press any key to exit"); 63 }); 64 65 try 66 { 67 Parallel.ForEach(nums, po, (num) => 68 { 69 double d = Math.Sqrt(num); 70 Console.WriteLine("{0} on {1}", d, Thread.CurrentThread.ManagedThreadId); 71 po.CancellationToken.ThrowIfCancellationRequested(); 72 }); 73 } 74 catch (OperationCanceledException e) 75 { 76 Console.WriteLine(e.Message); 77 } 78 finally 79 { 80 cts.Dispose(); 81 } 82 83 Console.ReadKey(); 84 } 85 #endregion 86 87 #region 异常处理 88 public static void TestException() 89 { 90 // Create some random data to process in parallel. 91 // There is a good probability this data will cause some exceptions to be thrown. 92 byte[] data = new byte[5000]; 93 Random r = new Random(); 94 r.NextBytes(data); 95 96 try 97 { 98 ProcessDataInParallel(data); 99 } 100 catch (AggregateException ae) 101 { 102 var ignoredExceptions = new List<Exception>(); 103 // This is where you can choose which exceptions to handle. 104 foreach (var ex in ae.Flatten().InnerExceptions) 105 { 106 if (ex is ArgumentException) 107 Console.WriteLine(ex.Message); 108 else 109 ignoredExceptions.Add(ex); 110 } 111 if (ignoredExceptions.Count > 0) throw new AggregateException(ignoredExceptions); 112 } 113 114 Console.WriteLine("Press any key to exit."); 115 Console.ReadKey(); 116 } 117 118 private static void ProcessDataInParallel(byte[] data) 119 { 120 // Use ConcurrentQueue to enable safe enqueueing from multiple threads. 121 var exceptions = new ConcurrentQueue<Exception>(); 122 123 // Execute the complete loop and capture all exceptions. 124 Parallel.ForEach(data, d => 125 { 126 try 127 { 128 // Cause a few exceptions, but not too many. 129 if (d < 3) 130 throw new ArgumentException($"Value is {d}. Value must be greater than or equal to 3."); 131 else 132 Console.Write(d + " "); 133 } 134 // Store the exception and continue with the loop. 135 catch (Exception e) 136 { 137 exceptions.Enqueue(e); 138 } 139 }); 140 Console.WriteLine(); 141 142 // Throw the exceptions here after the loop completes. 143 if (exceptions.Count > 0) throw new AggregateException(exceptions); 144 } 145 #endregion 146 } 147 }