如何使用带有串行内循环的openMP并行化外循环以进行数组添加

Posted

技术标签:

【中文标题】如何使用带有串行内循环的openMP并行化外循环以进行数组添加【英文标题】:How to parallellize an outer loop with openMP with serial inner loop for array addition 【发布时间】:2013-11-26 13:38:23 【问题描述】:

以下来自 C++ 函数的 sn-p 最初是作为串行代码编写的。 为了使外部循环与计数器'jC' 并行化,我刚刚添加了行 "#pragma omp parallel for private(jC)" 。尽管这种幼稚的方法帮助了我很多次,但我怀疑并行化 jC 循环是否足够,因为相对于原始代码,执行时间似乎没有变化。 有没有人提出一些建议来确保将以下代码有效地转换为(正确的)并行代码?

提前致谢,如果我的问题没有很好地提出,我深表歉意(这是我在这个论坛上的第一篇帖子)。

代码sn-p是:

#include "omp.h"

void  addRHS_csource_to_pcellroutine_par(
             double *srcCoeff, double *srcVal, int nPc,
             double *adata, double *bdata, int elsize
             )
   int elamax = elsize*elsize;
    int jC;
    #pragma omp parallel for private(jC)
    for (int jC=0; jC<nPc; jC++) 
         for (int el=0; el<elamax; el++) 

              adata[el + jC*elamax]    = adata[el + jC*elamax] - srcCoeff[el + jC*elamax];
         

         for (int el=0; el<elsize; el++) 

              bdata[el + jC*elsize]    = bdata[el + jC*elsize] + srcVal[el + jC*elsize];

         

    

附加说明:一种(可能不是最优雅的?)解决方法,包括将代码更改为

void  addRHS_csource_to_pcellroutine_parFunction(int jC, int elamax,
             double *srcCoeff, double *srcVal, int nPc,
             double *adata, double *bdata, int elsize
             )
   
    for (int el=0; el<elamax; el++) 

         adata[el + jC*elamax]    -= srcCoeff[el + jC*elamax];
    

    for (int el=0; el<elsize; el++) 

         bdata[el + jC*elsize]  += srcVal[el + jC*elsize];

    



void  addRHS_csource_to_pcellroutine_par(
             double *srcCoeff, double *srcVal, int nPc,
             double *adata, double *bdata, int elsize
             )
   int elamax = elsize*elsize;  
    #pragma omp parallel for  
    for (int jC=0; jC<nPc; jC++) 
         addRHS_csource_to_pcellroutine_parFunction(jC, elamax, srcCoeff, srcVal, nPc, adata, bdata, elsize);
    


【问题讨论】:

你有两个不同的 jC 变量。另外,我认为没有任何理由使用 private(jC)。 确实,在我看来,'#pragma omp parallel for '似乎更合理地使用 '#pragma omp parallel for private(jC)' ... 【参考方案1】:

正如您在specifcation 中看到的那样(第 55 页) 您的内部循环没有并行化。只有外层是。

int jC;
#pragma omp parallel for private(jC)
for (int jC=0;......

您已经定义了两个名为 jC 的变量。您打算做的是正确的,但您应该决定一种解决方案:

int jC;
#pragma omp parallel for private(jC)
for(jC = 0;....

#pragma omp parallel for
for(int jC = 0;....

至于:

我怀疑并行化 jC 循环是否足够, 因为执行时间似乎 相对于原始代码保持不变。

充分性取决于您必须执行的迭代次数(由 nPc 给出)和您提供的线程数(在四核 8 线程上合理)。 您甚至可以获得更慢的并行化循环。这是因为创建新线程的开销非常高(+ 一些其他额外的东西,比如管理线程)。

因此,您必须通过并行化循环来获得比创建线程所需的更多时间。

希望这能回答您的问题。

如果您仍然需要更快的程序,您可以考虑一种算法来并行化内部循环(例如,通过拆分迭代空间并使用 openmp reduction 构造)

【讨论】:

以上是关于如何使用带有串行内循环的openMP并行化外循环以进行数组添加的主要内容,如果未能解决你的问题,请参考以下文章

OpenMP 循环运行代码比串行循环慢

OpenMP 并行代码与串行代码的输出不同

带有 break openmp 的并行 If-else 循环

如何使用 OpenMP 通过 C++ std::list 并行化 for 循环?

OPENMP F90/95 嵌套 DO 循环 - 与串行实现相比得到改进的问题

如何优化并行嵌套循环?