使用OpenMP给程序加速(二)

OpenMP具体的使用方法及其注意事项。

 

首先声明本文主要是参考下面的网址内容进行的总结。详细信息可以参考下面的网址。

http://software.intel.com/zh-cn/articles/intel-guide-for-developing-multithreaded-applications/

 

 

对于多个嵌套式循环,选择最外层循环进行并行化最为安全。这种方法通常会生成最为粗糙的粒度。确保工作能够平均分配给每个线程。如果因最外层循环的迭代次数较低而无法实施平均分配,则最好选择具有较大迭代次数的内层循环进行线程分配。例如,考虑下面包含四个嵌套循环的代码:
  1. void processQuadArray (int imx, int jmx, int kmx, 
  2.   double**** w, double**** ws) 
  3.   for (int nv = 0; nv < 5; nv++) 
  4.     for (int k = 0; k < kmx; k++) 
  5.       for (int j = 0; j < jmx; j++) 
  6.         for (int i = 0; i < imx; i++) 
  7.           ws[nv][k][j][i] = Process(w[nv][k][j][i]); 

如果线程数量多余或少于五个,并行外部循环将会导致负载不平衡和闲置线程。如果阵列维数imxjmxkmx非常大的话,并行效率将会很低。这种情况下最好选择并行其中一个内部循环。

如果能确保安全性,应尽可能排除工作分享结构底端的隐性障碍。所有 OpenMP 工作分享结构(不论整段还是单个)均在结构块底端含有一个隐性障碍。只有所有线程都在此障碍处集合后,并行才能执行。有时,这些障碍很不必要,并且会影响性能。应使用 OpenMP nowait 子句来消除这些障碍,如下面这个示例:

  1. void processQuadArray (int imx, int jmx, int kmx, 
  2.   double**** w, double**** ws) 
  3.   #pragma omp parallel shared(w, ws) 
  4.   { 
  5.     int nv, k, j, i; 
  6.     for (nv = 0; nv < 5; nv++) 
  7.       for (k = 0; k < kmx; k++) // kmx is usually small 
  8.         #pragma omp for shared(nv, k) nowait 
  9.           for (j = 0; j < jmx; j++) 
  10.             for (i = 0; i < imx; i++) 
  11.               ws[nv][k][j][i] = Process(w[nv][k][j][i]); 
  12.   } 
  13. }

由于最内层循环的计算都是独立的,因此在进行下一次迭代之前,线程没有必要在隐性障碍处等待。如果每次迭代的工作量各不相同,nowaitnowait 子句可使线程继续处理有用工作,而非闲置在隐性障碍处。

如果一个循环带有一种可防止循环被并行执行的循环传递相关性,可以将循环体分裂成单独的循环,进而实现并行执行。一个循环体被划分为两个或两个以上的循环被称为“循环分裂”。下面的示例演示了循环分裂过程,一个具有循环传递相关性的循环体创建出新的循环,进而完成并行执行。

  1. float *a, *b; 
  2. int i; 
  3. for (i = 1; i < N; i++) { 
  4.   if (b[i] > 0.0)  
  5.     a[i] = 2.0 * b[i]; 
  6.   else  
  7.     a[i] = 2.0 * fabs(b[i]); 
  8.   b[i] = a[i-1]; 
  9. }

但是,若将一个循环体分裂成两个独立的操作,这两个操作均可并行执行,如下面的代码:

for  (i = 1; i < N; i++)     if  (b[i] > 0.0)       a[i] = 2.0 * b[i];     else        a[i] = 2.0 * fabs(b[i]);  } for(i = 1; i   b[i] = a[i-1]; 

 

 


 


你可能感兴趣的:(使用OpenMP给程序加速(二))