OpenMP 程序比顺序程序慢

Posted

技术标签:

【中文标题】OpenMP 程序比顺序程序慢【英文标题】:OpenMP program is slower than sequential one 【发布时间】:2012-05-24 09:10:58 【问题描述】:

当我尝试以下代码时

double start = omp_get_wtime();

long i;

#pragma omp parallel for
    for (i = 0; i <= 1000000000; i++) 
        double x = rand();
    

    double end = omp_get_wtime();

    printf("%f\n", end - start);

执行时间约为 168 秒,而顺序版本仅需 20 秒。

我还是并行编程的新手。如何获得比顺序版本更快的并行版本?

【问题讨论】:

【参考方案1】:

随机数生成器rand(3) 使用全局状态变量(隐藏在 (g)libc 实现中)。从多个线程访问它们会导致缓存问题,并且也不是线程安全的。您应该使用 rand_r(3) 调用和线程私有的 seed 参数:

long i;
unsigned seed;

#pragma omp parallel private(seed)

    // Initialise the random number generator with different seed in each thread
    // The following constants are chosen arbitrarily... use something more sensible
    seed = 25234 + 17*omp_get_thread_num();
    #pragma omp for
    for (i = 0; i <= 1000000000; i++) 
       double x = rand_r(&seed);
    

请注意,并行执行时与串行执行时会产生不同的随机数流。我还推荐erand48(3) 作为更好的(伪)随机数来源。

【讨论】:

还应该注意,由于double x = rand() 不修改外部状态,编译器可能会尝试在顺序版本中优化循环输出。一般来说,您应该使用无法优化的代码进行测试。 @Vanwaril, rand() 不是内在的。编译器不知道它是否是纯函数(它是 not),因此不应优化调用。 非常感谢。现在并行版本花费 5 秒,而顺序版本花费 9 秒。 @HristoIliev,编译器可能会识别rand()修改的状态,并且没有对rand()的外部调用,它很可能可以确定它不影响程序的输出/结果. rand() 是一个外部库函数。它在stdlib.h 中的声明没有办法说明它是否修改了外部状态,而且它的代码隐藏在已经编译的库中。 GCC 为纯外部函数提供了__atribute__ ((pure)) 显式注解。只需尝试编译启用最大优化的串行版本并亲自查看。

以上是关于OpenMP 程序比顺序程序慢的主要内容,如果未能解决你的问题,请参考以下文章

内部的openmp延迟

openMp改写的程序比串行还慢

在 OpenMp 中使用更多线程会减慢我的程序。串行速度比

在针对顺序运行进行优化的程序上使用 openMP 后没有性能提升

OpenMP 循环运行代码比串行循环慢

用 ISPC 编译器编译 OpenMP 程序