并行:指在同一时刻,有多条指令在多个处理器上同时执行
并发:指在同一时刻只能有一条指令执行,但多个进程指令被快速的轮换执行,使得在宏观上具有多个进程同时执行的效果,但在微观上并不是同时执行的,只是把时间分成若干段,使多个进程快速交替的执行
并发是逻辑上的同时发生(simultaneous),而并行是物理上的同时发生。
串行:A和B两个任务运行在一个CPU线程上,在A任务执行完之前不可以执行B。即,在整个程序的运行过程中,仅存在一个运行上下文,即一个调用栈一个堆。程序会按顺序执行每个指令。
1:并行Linq
System.Linq名称空间包含的类ParallelEnumerable可以分解查询的工作,使其分布在多个线程上。
尽管Enumerable类给IEnumerable
2:并行查询
对于可以放在CPU缓存中的小集合,并行Linq看不出效果。
AsParallel()方法用ParallelEnumerable()类定义,以扩展IEnumerable
集合可以分为多个部分,其中每个部分由不同的线程处理,以赛选其选项。,完成分区工作后,需要合并,获得所有部分的总和
1 static IEnumerable<int> SampleData() 2 { 3 const int arraySize = 50000000; 4 var r = new Random(); 5 return Enumerable.Range(0, arraySize).Select(x => r.Next(140)).ToList(); 6 }
static void Main(string[] args) { var data = SampleData(); var res = data.AsParallel().Where(x => Math.Log(x) < 4).Select(x => x).Average(); Console.WriteLine(res); }
data.AsParallel()这行代码从任务管理器,中可以看出系统的所有CPU利用率上升,使用多个cpu在运行,如果系统上没有多个cpu,就不会看到并行版本带来的改进。
下图为使用AsParaller()后的cpu使用率和所有处理器的百分比 12行代码使用率为13.04%左右
未使用AsParallel()
从上面两张截图可以看出 使用了AsParallel()的CPU的百分比是比未使用AsParallel()的百分比高的,但是cpu的使用率则是相反的。使用了AsParallel()的使用率会比没使用的会更低。
电脑配置说明:运行该例子的是双核cpu。
3:分区器
AsParallel()方法不仅扩展了IEnumerable
Partitioner类用System.Collection.Concurrent名称空间定义,并且有不同的变体。
Create()方法接受实现了IList
1 var result = 2 (from x in Partitioner.Create(data.ToList(), true).AsParallel() where Math.Log(x) < 4 select x).Average(); 3 Console.WriteLine(result);
也可以调用WithExecutionMode()和WithDegreeOfParallelism()方法,来影响并行机制。
对于WithExecutionMode()方法可以传递ParallelExecutionMode的一个Default值或者ForceParallelism值。 默认情况下,并行Linq避免使用系统开销很高的并行机制。
对于WithDegreeOfParallelism()方法可以传递一个整数值,以指定应并行运行的最大任务数。
查询不应使用全部CPU,这个方法会很有用
4:取消
.Net提供乐乐一种标准方式,来取消长时间运行的任务,这也适用于并行Linq。
要取消长时间运行的查询,可以给查询添加WithCancellation()方法,并传递一个CancellationToken令牌作为参数。
CancellationToken令牌从CancellationTokenSource类中创建。该查询在单独的线程中运行。
在该线程中,捕获一个OperationCanceledException类型异常。如果取消了查询。就触发这个异常,在主线程中,调用CancellationTokenSource类的Cancel()方案可以取消任务。
1 var cts = new CancellationTokenSource(); 2 Task.Run(() => { 3 try 4 { 5 var res = (from x in data.AsParallel().WithCancellation(cts.Token) where Math.Log(x) < 4 select x) 6 .Average(); 7 Console.WriteLine($"query finished,sum:{res}"); 8 } 9 catch (Exception e) 10 { 11 Console.WriteLine(e.Message); 12 }}, cts.Token); 13 Console.WriteLine("query start"); 14 Console.Write("Cancel?"); 15 string input = Console.ReadLine(); 16 if (input != null && input.ToLower().Equals("y")) 17 { 18 cts.Cancel(); 19 }