我有一段代码想并行化,而 openmp 程序比串行版本慢得多,那么我的实现有什么问题吗?。这是程序的代码
#include <iostream>
#include <gsl/gsl_math.h>
#include "Chain.h"
using namespace std;
int main(){
int const N=1000;
int timeSteps=100;
double delta=0.0001;
double qq[N];
Chain ch(N);
ch.initCond();
for (int t=0; t<timeSteps; t++){
ch.changeQ(delta*t);
ch.calMag_i();
ch.calForce001();
}
ch.printSomething();
}
Chain.h 是
class Chain{
public:
int N;
double *q;
double *mx;
double *my;
double *force;
Chain(int const Np);
void initCond();
void changeQ(double delta);
void calMag_i();
void calForce001();
};
Chain.cpp 是
Chain::Chain(int const Np){
this->N = Np;
this->q = new double[Np];
this->mx = new double[Np];
this->my = new double[Np];
this->force = new double[Np];
}
void Chain::initCond(){
for (int i=0; i<N; i++){
q[i] = 0.0;
force[i] = 0.0;
}
}
void Chain::changeQ(double delta){
int i=0;
#pragma omp parallel
{
#pragma omp for
for (int i=0; i<N; i++){
q[i] = q[i] + delta*i + 1.0*i/N;
}
}
}
void Chain::calMag_i(){
int i =0;
#pragma omp parallel
{
#pragma omp for
for (i=0; i<N; i++){
mx[i] = cos(q[i]);
my[i] = sin(q[i]);
}
}
}
void Chain::calForce001(){
int i;
int j;
double fij =0.0;
double start_time = omp_get_wtime();
#pragma omp parallel
{
#pragma omp for private(j, fij)
for (i=0; i<N; i++){
force[i] = 0.0;
for (j=0; j<i; j++){
fij = my[i]*mx[j] - mx[i]*my[j];
#pragma omp critical
{
force[i] += fij;
force[j] += -fij;
}
}
}
}
double time = omp_get_wtime() - start_time;
cout <<"time = " << time <<endl;
}
所以方法 changeQ() 和 calMag_i() 实际上比串行代码更快,但我的问题是 calForce001()。执行时间为:
- 使用 openMP 3.939s
- 没有 openMP 0.217s
现在,很明显我做错了什么或者代码无法并行化。请任何帮助有用。 提前致谢。 卡洛斯
编辑: 为了澄清这个问题,我添加了函数 omp_get_wtime() 来计算函数 calForce001() 的执行时间,一次执行的时间是
- 与 omp :0.0376656
- 没有 omp:0.00196766
因此使用 omp 方法慢 20 倍。
否则,我还要为 calMag_i() 方法计算时间
- 使用 omp:3.3845e-05
- 没有 omp:9.9516e-05
对于此方法,omp 快 3 倍。
我希望这可以确认延迟问题出在 calForce001() 方法中。
最佳答案
您无法从任何加速中获益的三个原因。
- 你的代码中到处都是
#pragma omp parallel
。这个 pragma 的作用是启动“线程团队”。在街区的尽头,这个团队被解散了。这是相当昂贵的。删除这些并使用#pragma omp parallel for
而不是#pragma omp for
将在第一次遇到时启动团队,并在每个 block 后使其休眠。这使我的应用程序速度提高了 4 倍。 - 您使用
#pragma omp critical
。在大多数平台上,这将强制使用互斥锁——这是一个激烈的竞争,因为所有线程都想同时写入该变量。所以,不要在这里使用临界区。你可以使用 atomic updates ,但在这种情况下,这不会有太大区别 - 请参阅第三项。仅删除关键部分即可将速度提高 3 倍。 - 只有当您有实际工作量时,并行才有意义。您的所有代码都太小,无法从并行性中获益。工作量太少,无法赢回在启动/唤醒/销毁线程时损失的时间。如果您的工作量是这个的十倍,一些
parallel for
语句就有意义了。但尤其是Chain::calForce001()
如果您必须进行原子更新,那将永远不值得。
关于编程风格:您正在使用 C++ 编程。请尽可能使用局部范围变量 - 例如Chain::calForce001()
,在内循环中使用局部double fij
。这使您不必编写 private
子句。编译器足够聪明,可以优化它。正确的范围界定可以实现更好的优化。
关于c++ - 内部的 openmp 延迟,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36121400/