并行开发基础
并行开发适合用于分解计算密集型的任务片段,并将它们分配给多个线程。
1、数据的并行处理
有一批数据,需要对每个元素进行相同的操作。该操作是计算密集型,需要耗费一定的时间。Parallel类型的 ForEach 方法就是专门为此设计的。
Parallel的ForEach可以对一系列值进行并行处理。还有类似的解决方案,就是PLINQ(并行LINQ)。
Parallel和PLINQ的区别:PLINQ假设可以使用计算机的所以CPU核,而Parallel会根据CPU的状态进行动态调整。
Parallel的ForEach是并行版本的foreach版本。Parallel类也提供了并行版本的for循环Parallel.For。如果有多个数组的数据,并且采用了相同的索引,Parallel.For方法就比较适合。
2、并行聚合
在并行操作结束时,需要集合结果,包括累加和、平均值等。
在Parallel中可以使用加锁的方法,来进行聚合。
PLINQ中聚合的支持,比Parallel类使用更顺手。
private static int ParallelSum(IEnumerable<int> values) { return values.AsParallel<int>().Sum(); }
3、并行调用
需要并行调用一批方法,并且这些方法(大部分)是互相独立的。 Parallel.Invoke方法就是用于这种场合。
例如并行调用一个方法10次:
private static void DoAction10Count(Action action) { Action[] actions = Enumerable.Repeat(action, 10).ToArray(); Parallel.Invoke(actions); }
对于简单的并行调用, Parallel.Invoke是一个不错的方式。但是,对于每一个输入都要调用一个操作,改用Parallel.Foreach,或者每一个操作要产生一个输出,改用PLINQ可能更好。
4、动态并行
并行任务的结构和数量要在运行时才能确定,这是一种更复杂的并行编程。
任务并行库(TPL)是以Task类为中心构建的。Parallel和PLINQ都是为了使用方便,对Task类的封装。
实现动态并行最简单的做法就是直接使用 Task 类。
在并行中是用Task和在异步中使用Task完全不同:
并行:并行任务可以使用阻塞的成员函数。例如:Task.WaitAll,Task.Wait,Taks.Result,Taks.WaitAny。并行任务通常也使用AttachedToParent来建立任务之间的父/子关系。
并行任务的创建需要使用Task.Run或者Task.Factory.StartNew方法。
异步:异步任务应该避免使用阻塞的成员函数。而应该使用await,Task.WhenAll、Taks.WhenAny。
5、并行LINQ
需要对一批数据进行处理,生成另外一批数据,或者对数据进行统计。
PLINQ为各种操作提供了并行操作,包括过滤、投影、聚合等。
PLINQ适合于对数据流进行操作,一个数据队列做为输入,一个数据队列做为输出。
上一篇: 我的程序人生(下)