带有 std::vector 的 OpenMP for 循环和带缩减的标量变量

OpenMP for loop with std::vector and scalar variable with reduction

我有这个代码:

#pragma omp declare reduction(* : scalar : omp_out *= omp_in)     
scalar like=1;
vector<scalar>& bigsum;
#pragma omp parallel for // reduction(* : like)    
for (int m = 0; m < M-1; m++)
   like *= bigsum[m];

我试图获得一致的结果,但它没有(竞争条件问题),但我应该如何解决它?因为它在代码中可见,所以我有自己的 reduction function,但它也不起作用。我应该知道标量和 std::vector 有什么技巧吗?

这里的标量变量只是通过在我创建的每个双精度上应用 log() 来覆盖浮点数,因为有太多的双精度乘法和双精度乘法,并且其中几个的结果接近于零。例如通过执行 log() 然后乘法变为加法等等。

一致答案的一个答案是:

    #pragma omp parallel
    {
       scalar loc = 1;
    #pragma omp for
       for (std::size_t m = 1; m < M;m++)
       {
          _flm[m-1] = Qratio[m-1] * k1 + k2;
          bigsum[m-1] = kappa0omegaproduct + kappa[1] * _flm[m-1];
    #pragma omp critical (reduce_product)
          {
             like *= bigsum[m-1];
          }
       }
}

这个答案是正确的,但是太慢了,在我的 8 核机器上几乎慢了 8 倍!

您的初始示例依赖于本机 OpenMP 缩减。您确定用户定义的 OpenMP 减少工作正常吗?这可能是重载运算符的问题。

你的第二个例子是正确的(你说的)但是由于临界区的原因很慢。为什么不通过每个线程有一个局部变量(例如 "local_like")然后在 "omp for"?

之后使用临界区来手动实施 OpenMP 缩减

三天后我自己有了答案,并解释了我的发现。

我创建了自己的缩减函数,如下所示:

#pragma omp declare reduction(* : scalar : omp_out *= omp_in) initializer (omp_priv (1))

诀窍是 omp_priv 显然减少值初始化很重要,这是我在 中学到的东西。

我通过像这样为循环应用 openmp 使代码更简单:

#pragma omp parallel for reduction (* : like)

非常简单干净。以这种新方式,代码得到并行化并且运行速度比我在问题正文中的代码运行得更快。不幸的是,它仍然比串行版本慢。也许是因为 std::vector 的用法,或者重载的算术运算很慢!?我不知道。代码太大了,我无法以一种可以理解的方式复制粘贴到这里,而不是让其他人阅读起来头疼。