【问题标题】:I am having trouble with OpenMP on C我在 C 上使用 OpenMP 时遇到问题
【发布时间】:2022-01-10 11:21:12
【问题描述】:

我想并行化 for 循环,但我似乎无法理解这个概念,每次我尝试并行化它们时它仍然有效,但速度显着减慢。

for(i=0; i<nbodies; ++i){
    for(j=i+1; j<nbodies; ++j) {
        d2 = 0.0;   
        
        for(k=0; k<3; ++k) {
            
            rij[k] = pos[i][k] - pos[j][k];
            
            d2 += rij[k]*rij[k];
        
        if (d2 <= cut2) {
           d = sqrt(d2);
           d3 = d*d2;
           
           for(k=0; k<3; ++k) {
                double f = -rij[k]/d3;
                forces[i][k] += f;
                forces[j][k] -= f;
           }
           
           ene += -1.0/d; 
        }
       }
    }
}

在某些情况下,我尝试使用带屏障和关键的同步,但没有任何反应,或者处理根本没有结束。

更新,这就是我现在的状态。在没有崩溃的情况下工作,但计算时间越长,我添加的线程越多。 (锐龙 5 2600 6/12)

#pragma omp parallel shared(d,d2,d3,nbodies,rij,pos,cut2,forces) private(i,j,k) num_threads(n)
    {
        clock_t begin = clock();
       #pragma omp for schedule(auto)
        for(i=0; i<nbodies; ++i){
            
            for(j=i+1; j<nbodies; ++j) {
                d2 = 0.0;
                for(k=0; k<3; ++k) {
                    rij[k] = pos[i][k] - pos[j][k];
                    d2 += rij[k]*rij[k];    
                }
                
                if (d2 <= cut2) {
                    d = sqrt(d2);
                    d3 = d*d2;
                #pragma omp parallel for shared(d3) private(k) schedule(auto) num_threads(n)
                 for(k=0; k<3; ++k) {
                    double f = -rij[k]/d3;
                    #pragma omp atomic 
                    forces[i][k] += f;
                    #pragma omp atomic
                    forces[j][k] -= f;
                    }
                    
                    ene += -1.0/d; 
                }
            }
        }
    
        clock_t end = clock();
        double time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
        #pragma omp single
        printf("Calculation time %lf sec\n",time_spent);
    }

我在实际的并行代码中加入了计时器(我认为这种方式快了几毫秒)。此外,我认为我得到了大多数共享和私有变量的权利。在文件中输出力。

【问题讨论】:

  • 如果您询问有关特定语言代码的问题,请不要标记其他语言。虽然它们看起来很相似,但 C 和 C++ 实际上是两种非常不同的语言。也请花一些时间阅读the help pages,阅读SO tour,阅读How to Ask,以及this question checklist。最后请学习如何edit您的问题以改进它们。
  • 请发帖minimal reproducible example。上面的代码缺少声明以及您尝试并行化循环的方式。

标签: c parallel-processing openmp


【解决方案1】:

解决了,原来我只需要

#pragma omp parallel for nowait

也不需要“原子”。

奇怪的解决方案,我不完全理解它是如何工作的,但它的输出文件也有 0 个损坏的结果。

【讨论】:

  • 请注意,您的 OpenMP 实现存在几个问题(例如数据竞争)。如果它不小心给出了正确的结果,并不意味着你的代码是正确的。
  • 我认为它涵盖了我的目标,我测试了很多次,我没有得到任何错误。当然,它可能不适用于其他类似的问题,但它对我有用,所以......“如果它没有坏就不要修复它” - 一些聪明人
【解决方案2】:

您应该始终在所需的最小范围内定义变量,尤其是在性能成为问题的情况下。 (请注意,如果这样做,您的编译器可以创建更高效​​的代码)。除了性能之外,它还有助于避免数据竞争。

我认为你放错了花括号,第一个 for 循环中的条件应该是 i&lt;nbodies-1。变量ene 可以使用归约来求和,为了避免数据竞争,必须使用原子操作来增加数组forces,因此您不需要使用慢速屏障或临界区。您的代码应如下所示(假设 int 用于索引,double 用于计算):

#pragma omp parallel for reduction(+:ene)
 for(int i=0; i<nbodies-1; ++i){
    for(int j=i+1; j<nbodies; ++j) {
        double d2 = 0.0;       
        double rij[3];
        for(int k=0; k<3; ++k) {
            rij[k] = pos[i][k] - pos[j][k];            
            d2 += rij[k]*rij[k];       
        }
        if (d2 <= cut2) {
           double d = sqrt(d2);
           double d3 = d*d2;
           
           for(int k=0; k<3; ++k) {
                double f = -rij[k]/d3;
                #pragma omp atomic
                forces[i][k] += f;
                #pragma omp atomic
                forces[j][k] -= f;
           }           
           ene += -1.0/d;         
       }
    }
 }
}

【讨论】:

  • 这里的循环前声明变量double (*pos)[3], (*forces)[3]; double rij[3], d, d2, d3, ene, cut2=1000.0; unsigned i, j, k, nbodies;
  • 另外,当我减少它崩溃的线程数时,我真的陷入了僵局。
  • 如需了解崩溃原因,请提供minimal reproducible example
  • 我通过设置私有和共享变量设法让它运行没有错误。但它仍然比串行处理慢,当我增加线程数时,计算时间会增加。我还注意到,当我使用超过 1 个线程时,输出已损坏,导致无法计算数据,这意味着我必须在某处同步它。
  • 你的意思是你的代码不能正常工作还是我在这里给你看的那个?很可能你有一个数据竞赛。请理解,在您向我们展示您是如何并行化您的代码之前,我们无法为您提供帮助。要找到性能问题,需要更多详细信息,可以通过minimal reproducible example 提供。
【解决方案3】:

如果不同步的工作量不是很大,那么使用障碍或其他同步会减慢您的代码速度。你的情况并非如此。您可能需要重新编写代码以删除同步。

您正在做类似 N 体模拟的事情。我在这里制定了几个解决方案:https://pages.tacc.utexas.edu/~eijkhout/pcse/html/omp-examples.html#N-bodyproblems

另外:你的 d2 循环是一个缩减,所以你可以这样对待它,但如果该变量是 i,j 迭代的私有变量可能就足够了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-06-14
    • 2020-12-23
    • 2021-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多