OpenMP 没有给出正确的结果和不同的时间

Posted

技术标签:

【中文标题】OpenMP 没有给出正确的结果和不同的时间【英文标题】:OpenMP doesn't give right result and different time 【发布时间】:2022-01-22 12:55:02 【问题描述】:

我是 OpenMP 的新手,现在我正在研究 atomic 的用法。每次跑步我都有不同的结果和时间。有时大约一分钟,有时大约 19 秒。

下面是我的代码:

#include <iostream>
#include<iomanip>
#include<cmath>
#include<omp.h>
#include"KiTimer.h"

int main() 

    using namespace std;

    const int NUM_REPEAT = 100000000;
    KiTimer timer;
    timer.MakeTimer(0, "ADD");
    timer.Start();

    double sum = 0., x = 0.;
#pragma omp parallel
    
#pragma omp single
        cout << "Thread num:" << omp_get_num_threads() << endl;
#pragma omp for private(x)
        for (int i = 0; i < NUM_REPEAT; i++) 
            x = sqrt(i);
#pragma omp atomic
            sum += x;
        
    

    cout << setprecision(20) << "total:" << sum << endl;
    timer.Stop();
    timer.Print();
    return 0;

以下是三个不同测试运行的结果:

    第一个结果:

    第二个结果:

    第三个结果:

【问题讨论】:

浮点加法有精度损失。 不要使用原子。您的 for 循环应标记为 reduction(+:sum) 好的,谢谢。我想我明白了。 您可以将运行结果包含为文本(在代码块中),而不是文本的屏幕截图。 好的,我接下来改进 【参考方案1】:

用OMP求和的正确方法是:

#pragma omp for reduction(+:sum)

而不是

#pragma omp for private(x)
...
#pragma omp atomic

据我所知,原子子句在执行过于频繁时会增加很大的开销(实际上就是这样)。

另外,x的范围可以大大缩小,简化代码:不需要使用private。

关于不同的结果,这是正常的,因为您在不同的执行中以不同的顺序添加浮点数。用小数操作大数时问题更大,因为它们需要在操作时进行归一化并且会降低精度。双打的情况下,精度是15位,所以如果你加1000000000000000 + 1,结果还是1000000000000000,即使你做了很多次。

【讨论】:

谢谢你的回答,加深了我的理解。

以上是关于OpenMP 没有给出正确的结果和不同的时间的主要内容,如果未能解决你的问题,请参考以下文章

为啥这段代码(在 Matlab 的 MEX 文件中使用 OpenMP)给出不同的结果?

OpenMP 嵌套循环任务并行性,计数器未给出正确结果

OpenMP 并行代码与串行代码的输出不同

OpenMP - 循环中最简单的累加器给出不正确的结果

Openmp 多线程代码在使用多个线程时给出不同的答案

如何使用 OpenMP 在 GPU 上分配团队?