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 }