c++ - 内部的 openmp 延迟

标签 c++ performance parallel-processing openmp

我有一段代码想并行化,而 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/

相关文章:

C++: ":"到底在做什么?

C++ 将字符串引用传递给函数

c++ - 为什么经常用 FLOPS 来比较数学库?

java - 确定嵌套消费者完成情况

multithreading - Valgrind 处理线程和机器级同步指令的效果如何?

c++ - 区间函数

python - 将分配分成两行仍然有效吗?

performance - Matlab tic toc 精度

parallel-processing - Nifi- 使用 ExecuteStreamCommand 并行和并发执行

c++ - Microsoft Visual Studio C++ 2013 链接错误(使用 SQLite 包装器时)