并行计算之计算模型

    随着海量数据处理的需求增加,并行计算越来越发挥它巨大的作用。通过采用多线程(多进程)的模式对同一任务进行并行处理,可以大大节省处理时间,提高处理效率。

并行算法可以通过数据划分,得到相应的任务即,然后映射到多个进程。接下来让我们一窥究竟。

   
划分数据
    我们知道算法就是作用于输入数据,得出一组输出数据。那么进行并行计算的一种模式就是对数据进行划分,包括:划分输入数据、划分输出数据、划分中间数据。
1) 划分输入数据
  例1:计算从从1到n的自然数哪些是素数
  那么将长度为n划分为p个区间,每个任务判定对应自然数区间的素数。

2) 划分输出数据
  例2:两个矩阵A、B相乘,那么每个矩阵都可以分解为4个矩阵块。

每个输出块都可以独立算出
   Task1:C11 = A11B11 + A12B21
   Task2:C12 = A11B12 + A12B22
   Task3:C21 = A21B11 + A22B21
   Task4:C22 = A21B12 + A22B22
   那么根据输出数据划分的4个任务都可以独立地计算出,最大并发度为4

3) 划分中间数据

   例3:还是例2中的问题,我们知道以输出矩阵C的 2x2的划分的最大并发度为4,其实对于每个任务我们可以划分更加细致。


  其中每个任务划分如下:

   Task1:E11 = A11B11

   Task2:E12 = A11B12 
   Task3:E21 = A21B11 
   Task4:E22 = A21B12 
   Task5:F11 = A12B21
   Task6:F12 = A12B22
   Task7:F21 = A22B21
   Task8:F22 = A22B22
   Task9:C11 = E11 + F11
   Task10:C12 = E12 + F12
   Task11:C21 = E21 + F21

   Task12:C22 = E22 + F22

   先计算来个中间矩阵,然后对这2个中间矩阵求和。


并行算法性能评价
    我们知道一个好的并行算法具有较高的加速比,也就是说具有尽可能大的平均并发度,它是描述并行程序性能一个非常重要的指标。
一般来说并行算法都可以用一个任务依赖图进行描述,我们可以通过任务依赖图来得到平均并发度
    平均并发度 = 总任务大小 / 关键路径长度

其中关键路径长度是任务依赖图中任何一对起始节点和终止节点之间的最长有向图路径,是整个并行算法瓶颈所在。

    以平均平均并发度的标准来衡量矩阵相乘中的两种算法:划分输出数据和划分中间数据,分别在(a)和(b)中得到它们的平均依赖图,以及每个任务的大小。


对于划分输入数据:

     关键路径为n^3/4, 总的任务为n^3,平均并发度为4

对于划分中间数据:

    关键路径为n^3/8+n^2/4,总的任务为n^3,平均并发度约为8

由上面的过程可以看出,为了有效的进行并行计算,划分的各个人间最好相互独立,并尽可能减少划分的r任务粒度。

负载平衡的映射技术
   以例1为例,如果有p个进程,可以用以下三种负载平衡方案:
1)静态映射方案
   并行算法如例1所示,伪代码如下所示:
   void PrimePrint()
   {
      int id = ThreadID.get();
      int block = n / p;
      for(int j= id * block; j< (id+1) * block; ++j)
        if(isPrime(j))
          print(j); 
   }
       每个进程判定相应的区间的素数。但是这种静态映射方案存在着任务不均衡的问题,我们知道自然数越大判定它是否是素数花费的时间越长,因此p个任务
严重不均衡。同时在实际的任务中,我们也无法容易的确定每个任务大小以及任务间交互特点,因此采用静态映射方案的缺点是可能存在着负载不均衡,优点是很容易设计和编程。

2)集中式方案
   可以将所有可执行的任务维护在一个公用的中心数据结构, 以例1为例,伪代码如下图所示
   void PrimePrint()
   {
      i = counter.getAndIncrement();   //原子加1
        if(isPrime(j))
          print(j); 
   }
   也可以在主进程中维护一个任务池,其他集成通过主进程获取一部分可用的任务,当新任务产生的时候会被添加到主进程的任务池中。集中式映射方案负载平衡性比较好,但是一个缺点是可能限制可扩展性,如果使用的进程越来越多,大量访问公用数据结构或主进程就会导致瓶颈。

3)分布式方案
   采用这种方案中,可执行任务集分布在多个进程中。每个进程在预先设定的任务执行完后可以从其他进程“窃取”任务。这种方案非常灵活,但设计和编程实现难度较大。

你可能感兴趣的:(多核编程与并行计算)