我有一段代码需要并行化,而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()。执行时间是:
现在,显然我做错了什么或代码无法并行化。请任何有用的帮助。 提前致谢。 卡洛斯
编辑: 为了澄清这个问题,我添加了函数omp_get_wtime()来计算函数 calForce001()的执行时间,以及一次执行的时间
因此,使用omp方法慢20倍。
否则,我还会计算 calMag_i()方法的时间
对于这种方法,omp 快3倍。
我希望这可以确认延迟问题是在calForce001()方法中。
答案 0 :(得分:3)
有三个理由说明你没有从任何加速中受益。
#pragma omp parallel
。这个pragma的作用是启动“线程团队”。在该区块结束时,该团队被解散。这是非常昂贵的。删除这些并使用#pragma omp parallel for
代替#pragma omp for
将在第一次遇到时启动团队并在每个块之后将其置于睡眠状态。这使得应用程序对我来说快了4倍。#pragma omp critical
。在大多数平台上,这将强制使用互斥锁 - 因为所有线程都希望同时写入该变量,因此这种互斥是非常争用的。所以,不要在这里使用关键部分。您可以使用atomic updates,但在这种情况下,这不会产生太大影响 - 请参阅第三项。只需删除关键部分就可以将速度提高3倍。parallel for
语句中的就会有意义。但是如果你必须进行原子更新,尤其Chain::calForce001()
永远不值得。关于编程风格:你用C ++编程。请尽可能使用本地范围变量 - 例如Chain::calForce001()
,在内部循环中使用本地double fij
。这样您就不必编写private
条款。编译器非常聪明,可以对其进行优化。正确的范围允许更好的优化。