我正在尝试使用OpenMP。我写了一些代码来检查它的性能。在使用Kubuntu 11.04的4核单Intel CPU上,使用OpenMP编译的以下程序比没有OpenMP编译的程序慢大约20倍。为什么呢?
我用g ++编译了它-g -O2 -funroll-loops -fomit-frame-pointer -march = native -fopenmp
#include <math.h>
#include <iostream>
using namespace std;
int main ()
{
long double i=0;
long double k=0.7;
#pragma omp parallel for reduction(+:i)
for(int t=1; t<300000000; t++){
for(int n=1; n<16; n++){
i=i+pow(k,n);
}
}
cout << i<<"\t";
return 0;
}
答案 0 :(得分:15)
问题是变量k被认为是共享变量,因此必须在线程之间同步。 避免这种情况的可能解决方案是:
#include <math.h>
#include <iostream>
using namespace std;
int main ()
{
long double i=0;
#pragma omp parallel for reduction(+:i)
for(int t=1; t<30000000; t++){
long double k=0.7;
for(int n=1; n<16; n++){
i=i+pow(k,n);
}
}
cout << i<<"\t";
return 0;
}
在下面的评论中跟随Martin Beckett的提示,不是在循环中声明k,而是在循环外声明k const。
否则,ejd是正确的 - 这里的问题似乎并不是很糟糕的并行化,但代码并行化时的优化不好。请记住,gcc的OpenMP实现非常年轻,远非最佳。
答案 1 :(得分:3)
最快的代码:
for (int i = 0; i < 100000000; i ++) {;}
代码稍慢:
#pragma omp parallel for num_threads(1)
for (int i = 0; i < 100000000; i ++) {;}
代码慢2-3倍:
#pragma omp parallel for
for (int i = 0; i < 100000000; i ++) {;}
无论{和}之间是什么。一个简单的 ;或更复杂的计算,相同的结果。我使用gcc和g ++在Ubuntu 13.10 64位下编译,尝试使用不同的参数-ansi -pedantic-errors -Wall -Wextra -O3,并在Intel四核3.5GHz上运行。
我猜线程管理开销是错误的? OMP每次需要时创建一个线程并在之后将其销毁,这似乎并不聪明。我以为会有四(或八)个线程在需要或睡觉时运行。
答案 2 :(得分:0)
我在GCC上观察到类似的行为。但是我想知道在我的情况下它是否与模板或内联函数有某种关系。您的代码是否也在模板或内联函数中?请查看here。
但是对于非常短的for循环,你可能会发现一些与线程切换相关的小开销,如你的情况:
#pragma omp parallel for
for (int i = 0; i < 100000000; i ++) {;}
如果你的循环执行了几毫秒甚至几秒的非常长的时间,你应该在使用OpenMP时观察性能的提升。但只有当你有多个CPU时。您拥有的内核越多,OpenMP的性能就越高。