说明:
在Parallel类中提供了三个静态方法作为结构化并行的基本形式:
- Parallel.Invoke方法:并行执行一组委托。
- Parallel.For方法:执行与C# for循环等价的并行方法。
- Parallel.ForEach方法:执行与C#foreach循环等价的并行方法。
这三个方法都会阻塞线程直到所有工作完成为止。和PLINQ一样,在出现未处理异常之后,其他的工作线程将会在其当前迭代完成之后停止,并将异常包装为AggregateException抛出给调用者。
1. 与PLINQ一样,Parallel.*方法是针对计算密集型任务而不是I/O密集型任务进行优化的。
2. 循环是无序的,如果需要顺序,直接使用同步。
3. 如果用到共享变量,要使用线程同步锁。
4. 如果虽是大量,但简单无等待的操作,同步执行可能更快。
5. 如果是带数据库操作,请使用事务,注意错误处理。
6. ForEach 比For效率更高。
一: Parallel.Invoke:并行执行一组Action委托,然后等待它们完成(尽可能的同时执行)。
1. 该方法最简单的定义方式如下:public static void Invoke (params Action[] actions);
2. 如果任务不超过10个,建议直接用Task,因为不超过10个的时候,Invoke内部会使用Task.Factory.StartNew创建任务。直接用Task.Factory.StartNew或者Task.Run效率更高。
3. 适合用于执行大量且无返回值的场景:如果将一百万个委托传递给Parallel.Invoke方法,它仍然能够有效工作。这是因为该方法会将大量的元素划分为若干批次(自动分批处理),并将其分派给底层的Task。
1 #region 第一种模式 2 static void ParallelInvoke1() 3 { 4 Parallel.Invoke(Fun1, Fun2); 5 } 6 static void Fun1() 7 { 8 Console.WriteLine("Fun1"); 9 } 10 static void Fun2() 11 { 12 Console.WriteLine("Fun2"); 13 } 14 #endregion 15 #region 第二种模式 16 static void ParallelInvoke2() 17 { 18 Action action = () => 19 { 20 Console.WriteLine($"Thread Id:{Thread.CurrentThread.ManagedThreadId }"); 21 }; 22 Parallel.Invoke(action, action, action, action, action, action, action, action, action, action, action, action); 23 Console.WriteLine("Parallel.Invoke 执行完成"); 24 } 25 #endregionParallel.Invoke
二. Parallel.For使用(无序的),适合带索引的大量循环操作
// 顺序 for(int i=0; i<100; i++) Foo(i); // 并行话代码 Parallel.For(0, 100, i=> Foo(i)); // 简洁写法 Parallel.For(0, 100,Foo);View Code
Parallel Options选项配置,有三个属性
1. Cancellation Token 取消任务,并且处理任务被取消后的一些操作
2. MaxDegreeOfParallelism 设置最大并发数,默认-1
3. TaskScheduler指定任务调度器。
ParallelLoopResult 并发结果,有两个属性
1. IsCompleted 任务是否执行完成。
2. LowestBreakIteration 调用Break方法的最小任务索引(小于这个的索引都要执行)
ParallelLoopState,由于并行的For或ForEach的循环体是一个委托,因此无法使用break语句提前结束循环。但是可以调用ParallelLoopState对象的Break方法或Stop方法来跳出或者结束循环
Break
Stop
1 /// <summary> 2 /// Parallel.For使用 3 /// </summary> 4 /// <param name="num"></param> 5 static void ParallelForFun(int num) 6 { 7 Console.WriteLine($"ParallelFor执行总次数:{num}"); 8 var list = new List<dynamic>() ; 9 ParallelLoopResult result = Parallel.For(0, num, i => 10 { 11 list.Add(new Product { Id = i, nameof = "Testname" }); 12 Console.WriteLine($"Task ID:{Task.CurrentId},Thread:{Thread.CurrentThread.ManagedThreadId }"); 13 Thread.Sleep(20); 14 }); 15 }View Code
a. 循环中断:Parallel.For带ParallelLoopState(执行状态,可以中途取消),带ParallelLoopResult(执行结果)
1 static void ParallelForAsyncAbort() 2 { 3 4 ParallelLoopResult result = 5 Parallel.For(10, 100, async (int index, ParallelLoopState pls) => 6 { 7 Console.WriteLine($"Index:{index} task:{Task.CurrentId},Thread:{Thread.CurrentThread.ManagedThreadId }"); 8 await Task.Delay(10); 9 if (index > 30) 10 pls.Break(); 11 }); 12 Console.WriteLine($"Is completed:{result.IsCompleted} LowestBreakIteration:{result.LowestBreakIteration }"); 13 }View Code
Break:不立马结束循环,而是等所有小于ParallelLoopResult.LowestBreakIteration 的迭代执行完,才结束循环。(用Break时,记得要用大于的条件判断)
Stop:不用等,可以更快捷的结束循环。
Break与Stop都不能停止已经开始的迭代,只可以防止新的迭代开始。
b.循环取消:
1 static void ParallelForCancel() 2 { 3 4 var cts = new CancellationTokenSource(); 5 cts.Token.Register(() => { Console.WriteLine($"*** token canceled"); }); 6 cts.CancelAfter(500);//执行500毫秒后取消 7 try 8 { 9 ParallelLoopResult result = Parallel.For(0, 100, new ParallelOptions() 10 { 11 CancellationToken = cts.Token, 12 }, x => 13 { 14 Console.WriteLine($"loop {x} started"); 15 int sum = 0; 16 for (int i = 0; i < 100; i++) 17 { 18 Thread.Sleep(2); 19 sum += 1; 20 } 21 Console.WriteLine($"loop {x} finished"); 22 }); 23 } 24 catch (OperationCanceledException ex) 25 { 26 Console.WriteLine(ex.Message); 27 } 28 }循环500毫秒后取消
执行结果,可以看出,取消后,已经开始的任务,还是会继续执行完成
三:Parallel.ForEach(大数据集的循环执行,例如:数组,集合,枚举)
1 // 执行结果是无序的 2 static void ParallelForEach1() 3 { 4 string[] data = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten" }; 5 ParallelLoopResult result = Parallel.ForEach(data, a => 6 { 7 Console.WriteLine(a); 8 9 }); 10 11 } 12 static void ParallelForEach2() 13 { 14 string[] data = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight","nine","ten" }; 15 16 ParallelLoopResult result = Parallel.ForEach<string>(data,(str,psl,index)=> 17 { 18 Console.WriteLine($"str:{str} index:{index}"); 19 20 }); 21 22 }ParallelForEach
结果是无序的
标签:Console,C#,void,编程,static,WriteLine,action,Parallel From: https://www.cnblogs.com/apple-hu/p/18321407