【发布时间】:2017-08-18 11:40:24
【问题描述】:
我正在尝试将 openMP 并行化添加到一个相当大的项目中,但我发现 openMP 在并行块之外在并行块之外进行了太多同步。
这种同步是针对所有变量完成的,即使是那些未在并行块中使用的变量,它也是连续完成的,不仅在进入块之前。
我举了一个例子来证明这一点:
#include <cmath>
int main()
{
double dummy1 = 1.234;
int const size = 1000000;
int const size1 = 2500;
int const size2 = 500;
for(unsigned int i=0; i<size; ++i){
//for (unsigned int j=0; j<size1; j++){
// dummy1 = pow(dummy1/2 + 1, 1.5);
//}
#pragma omp parallel for
for (unsigned int j=0; j<size2; j++){
double dummy2 = 2.345;
dummy2 = pow(dummy2/2 + 1, 1.5);
}
}
}
如果我运行此代码(注释了 for 循环),运行时间为 6.75 秒(带并行化)和 30.6 秒(不带并行化)。太好了。
但是如果我取消注释 for 循环并再次运行它,过度同步就会启动,我得到的结果是 67.9s 并行化和 73s 没有并行化。如果我增加 size1,我什至会得到比没有它的并行化更慢的结果。
有没有办法禁用此同步并仅在第二个 for 循环之前强制它?或者任何其他方式如何提高速度?
请注意,在实际示例中,外部循环都不是第一个 for 循环。外层实际上是一个 ODE 求解器,而第一个内层是更新内部值的负载。
我正在使用 gcc (SUSE Linux) 4.8.5
感谢您的回答。
【问题讨论】:
-
这个问题没什么意义。您是说在 OpenMP 之外添加工作会增加执行时间。这很令人惊讶吗?如果您运行代码时将您的虚拟循环注释掉,而您的 OpenMP 循环完全注释掉,您会发现第一个循环需要时间!您似乎已经得出了一个结论(OpenMP 正在做一些它没有做的事情)没有任何证据!
-
这段代码正确吗?
dummy1似乎没有在并行循环中使用。另外,您是否独立地为第一个和第二个循环计时?可能是第一个循环需要很长时间来处理,以至于并行化对第二个循环的影响在一起测量时并不明显。 -
@Tudor 这段代码不应该做任何可用的事情,它只是一个例子。
-
@JimCownie:我认为测量的数字很清楚:如果我们只看没有并行化的结果,我们会得到第二个 for 循环需要 30.6 秒,第一个循环需要 73-30.6 = 42.4 秒。至于并行化的结果,第二个循环需要 6.75 秒,而第一个循环需要 67.9-6.75 = 61.15 秒。现在我希望您看到,增加的工作不仅是由 for 循环本身造成的,而且还有一些额外的东西——由 openMP 引起的。我希望我说得更清楚。
-
@David Sery:这可能是因为您在两个循环中使用了相同的变量名。您是否尝试在第一个循环中将
j更改为其他内容?
标签: c++ performance optimization parallel-processing openmp