OpenMP 用于带有 std::vector 和标量变量的循环,带有缩减
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 倍!
三天
后我自己有一个答案,并对我的发现有一个解释。
我创建了自己的归约函数,如下所示:
#pragma omp declare reduction(* : scalar : omp_out *= omp_in) initializer (omp_priv (1))
诀窍是omp_priv,显然减少值初始化很重要,我在这里学到了一些东西。
我通过对这样的循环应用 openmp 使代码简单得多:
#pragma omp parallel for reduction (* : like)
非常简单干净。以这种新方式,代码得到并行化,并且运行速度比我在问题正文中的速度更快。不幸的是,它仍然比串行版本慢。也许是因为 std::vector 的使用,或者重载的算术运算非常慢!?我不知道。代码是如此之大,我无法以可以理解的方式将其复制粘贴到此处,并且对于其他人来说阅读也不会很痛苦。
您的初始示例依赖于本机 OpenMP 缩减。您确定用户定义的 OpenMP 缩减工作正常吗?这可能是重载运算符的问题。
你的第二个例子是正确的(你说的),但由于关键部分,速度很慢。为什么不手动实现 OpenMP 缩减,方法是在每个线程上有一个局部变量(例如"local_like"),然后在"omp for"之后使用关键部分?
相关文章:
- 是否可以禁止在for循环体内部修改循环变量
- 使用 size_t 初始化循环变量时的整数下溢
- 在循环中重新声明 for 循环变量时出错
- 为什么这个循环变量在循环范围之外是可访问的
- 关于循环变量优化的标准合规行为是什么?
- 用于 C/C++ 中的循环变量优化
- C++循环变量按另一个变量递增
- 使用循环变量作为C++数组的索引
- 如何循环变量
- 如何在字符串(名称)中使用循环变量
- strlen函数与循环不兼容,循环变量不兼容
- 使用浮点/双精度作为循环变量
- C 或 C++ :表示循环变量
- 为循环变量声明键入 int32_t
- 使用 if 语句交换循环变量
- OpenMP中调度程序对循环变量的处理
- 对于C++中的循环-变量没有正确递增
- C++11 基于范围的 for 循环,无循环变量
- 在循环之外使用for循环变量是错误的吗?
- For循环变量无缘无故地下地狱