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 程序比顺序程序慢的主要内容,如果未能解决你的问题,请参考以下文章