I. 设置Parallel Loop选项
我们可以为Parallel Loop设置一个ParallelOptions类的实例来影响Parallel Loop的行为,ParallelOptions有三个Properties
CancellationToken | 获得或设置一个CancellationToken |
MaxDegreeOfParallelism | 为一个Parallel Loop设置一个最大并发数,如果这个属性被设置为-1相当于没有为起设置最大并发数 |
TaskScheduler | 为一个Parallel Loop设置一个task scheduler,如果这个值为null,系统将提供一个默认的task scheduler |
关于CancellationToken和TaskScheduler我们将在后续章节中详细说明。
II. 停止或者中断 Parallel Loop
在通常的for和foreach循环中,我们可以使用break, continue等关键字控制循环的执行,比如我们使用break跳出一个循环的执行。在Parallel Loop中,.NET Framework提供了ParallelLoopState类来达到同样的效果.
.NET Framework提供了一些重载版本的Parallel.For和Parallel.Foreach,在第二个参数Action中,我们可以提供一个ParallelLoopState来实现前面所说的效果。
1: static void Main(string[] args)
2: {
3:
4: List<string> BrowserList = new List<string> { "IE6", "IE8", "IE9", "Firefox", "Safari", "Chrome", "opera" };
5: Parallel.ForEach(BrowserList, (string item, ParallelLoopState LoopState) =>
6: {
7: if (item == "Safari")
8: {
9: Console.WriteLine("The browser is: {0}", item);
10: LoopState.Stop();
11: }
12: });
13:
14: Console.ReadLine();
15: }
Stop(): 调用这个方法的时候,系统会使Parallel Loop尽快停止,但是它不能保证已经在运行的循环体立刻停止下来,比如一些已经处在运行中的循环体,仍有可能继续运行。
Break(): 调用这个方法的时候,系统会停止已经执行的循环体, 它跟Stop()的不同点在于,假设系统要执行100个循环体,在第33个时候,系统执行了break(),那么break()可以保证,第33个以后的循环体不会被执行。
下面这个表格列出了ParallelLoopState的所有成员:
Stop() | Communicates that Parallel Loop should cease execution at the system’s earlist convenience |
Break() |
Communicates that Parallel loop should cease execution at the system's earliest convenience of iterations beyond the current iteration |
IsExceptional | 如果一个循环体内抛出异常,它的值就是true |
IsStopped | 如果有一个循环体调用了Stop()方法,它的值就是true |
LowestBreakIteration | Return the index of the lowest iteration in which Break() was called. |
ShouldExitCurrentIteration | 如果循环体应该退出,它的值就是true |
上面几句担心自己翻译的不准确,所以用了英文;大家可以自己去理解其中的含义。
注意:ParallelLoopState是由Parallel类自动生成的,也就是说它存在于Parallel Loop的上下文中,我们不需要new 一个实例,就可以直接使用它。
III. 取消 Parallel Loop
Parallel Loop在执行过程中会监控ParallelOptions提供的CancellationToken,当一个CancellationTokenSource调用了Cancel()方法后, Parallel Loop将不会启动任何新的循环体,但是正在运行循环体会被执行结束,这时系统会抛出一个OperationCancellationException。
IV. 获得Parallel Loop的执行结果,捕获Parallel Loop的Exception
1. Parallel Loop执行完后返回一个ParallelLoopResult的结构体。它有两个属性LowestBreakIteration和IsCompleted,大家通过字面就能理解它的含义。
2. 在顺序执行的环境中,代码抛出一个异常后,我们可以立即处理。但是在并行环境中,一个循环体抛出一个异常后,系统对异常的处理方式与顺序环境完全不同。
在并行环境中,一个循环体抛出一个异常后,它会被放到一个System.AggregateException的异常集合,最后统一被处理。
1: static void Main(string[] args)
2: {
3:
4: List<string> BrowserList = new List<string> { "IE6", "IE8", "IE9", "Firefox", "Safari", "Chrome", "opera" };
5:
6: try
7: {
8: ParallelLoopResult plr = Parallel.ForEach(BrowserList, (string item, ParallelLoopState LoopState) =>
9: {
10: if (item == "Safari")
11: {
12: Console.WriteLine("The browser is: {0}", item);
13: LoopState.Break();
14: }
15: });
16: }
17: catch (System.AggregateException ex)
18: {
19: foreach (Exception innerEx in ex.InnerExceptions)
20: {
21: //your codes
22: }
23:
24: }
25:
26: Console.ReadLine();
27: }