初识Parallel ExtensionsTPL

LazyBee

上一篇我们介绍了Parallel Extensions中的PLINQ(具体请参考:初识Parallel ExtensionsPLINQ,今天我们来看看Parallel Extensions的另外一个组成部分任务并行库TPL(Task Parallel Library),TPL也是Parallel FX的关键组件之一。TPL的设计的目的是为了开发人员能够非常简单的使用TPL来编写可自动使用多处理器的托管代码,以提高程序运行的速度。PLINQ实现了以声明的方式(使用AsParallel)对数据源进行并行化的查询,而TPL是通过命令的方式将面向数据的操作(如for,foreach循环)以及轻量级的任务自动的运行在并行硬件上。

如果我们希望在我们程序中使用TPL的话,和PLINQ一样,首先我们需要引用System.Threading.dll文件,由于TPL的类主要是放在System.ThreadingSystem.Threading.Tasks命名空间中,所以需要在我们的类文件中用using关键字将这两个命名空间添加进去。下面我们就将我们的关注点放在这两个命名空间。

结构化并行性

最普通的面向数据的操作就是循环,将循环并行化是并行程序的关键点之一。TPL提供了For, ForEachDo三个命令来将循环并行化。这三个命令都是System.Threading.Parallel类的静态方法。下面我们就来详细看一下这三个静态方法:

For

矩阵相乘,大家在学校的《线性代数》课上肯定都学过,不过到现在肯定都忘的光光的了,我也是现上网去搜了搜(呵呵,寒)。也就是说一个MXN的矩阵去乘以一个NXP的矩阵,就可以得到一个MXP的矩阵。其公式是:


下面我们就看看使用C#实现的矩阵相乘:

初识Parallel Extensions之TPLclass Matrix<T>

有可能要进行相乘矩阵可能非常大(比如说500X500),我们可以利用TPL为我们提供Parallel.For来加快我们的计算速度,其定义为:

public static void For(int fromInclusive,int toExclusive,   Action<int> body)

其中:fromInclusive是循环的起始值

      toExclusive:循环的结束值

Action<int>:每一次循环要执行的操作,该操作有一个int的输入参数,也就是循环

的索引,没有返回值。

 

将循环并行化的矩阵相乘的代码如下:

初识Parallel Extensions之TPLpublic static Matrix<double> MultiplyParallel(Matrix<double> m1, Matrix<double> m2)

在我的机器上两个随机产生的500X500double的矩阵相乘,非并行化版本与并行化版本运行的时间比平均为1.98.效果还是比较明显的,大家也可以在自己的机器上试试。

    同时,针对不同的情况Parallel.For也提供了重载版本。比如说我们需要在一个非常大的数据列表中查找指定的数据,在找到第一个数据之后就退出查找循环,这时候我们就可以使用下面这个重载版本:

public static void For(int fromInclusive,int toExclusive,Action<int, ParallelState> body)

前面两个参数也是循环的起始值和结束值。不同的就是每次循环要执行的操作,该操作多了一个ParallelState类型的输入参数,ParallelState有一个Stop方法,用于终止循环。

    如果我们需要计算指定范围内的所有素数之和,这是我们可以利用Parallel.For的另外一个重载:

public static void For<TLocal>(int fromInclusive,int toExclusive,

Func<TLocal> threadLocalSelector,

                                    Action<int, ParallelState<TLocal>> body,

                                    Action<TLocal> threadLocalCleanup)

前面两个参数同样是循环的起始值和结束值,threadLocalSelector是产生本地状态的函数,body是每次循环(迭代)要进行的处理操作,threadLocalCleanup是用于清理线程本地状态的操作。这时我们计算素数之和的代码片段如下:

初识Parallel Extensions之TPLint sum = 0;
初识Parallel Extensions之TPLParallel.For(
010000, () => 0, (i,state)=>

()=>0就是告诉编译器state.ThreadLocalState中存放的数据类型是int型,并且将其初始化为0,在执行完循环之后,将所有线程中的ThreadLocalState的值相加来得到最终的素数之和。例子中partialSum就是表示ThreadLocalState的参数。
你也可以使用这个重载来取出所有的素数(当然你也可以使用PLINQ来做):

初识Parallel Extensions之TPLList<int> results = new List<int>();
初识Parallel Extensions之TPLParallel.For(
010000, () => new List<int>(),(i, state) =>
注:这里isPrime是判断是否是素数的函数。(未完待续)

相关文章:

  • 2021-12-06
  • 2021-12-14
  • 2021-07-05
  • 2022-02-11
  • 2022-01-09
  • 2022-12-23
  • 2022-02-10
猜你喜欢
  • 2021-12-29
  • 2021-12-23
  • 2021-10-27
  • 2021-07-14
  • 2021-07-02
  • 2021-07-04
  • 2022-12-23
相关资源
相似解决方案