openmp代码有缩减和不缩减两种版本。
//减少
#pragma omp parallel for reduction(+:sum)
for (i=1;i<= num_steps; i++){
x = (i-0.5)*step;
sum = sum + 4.0/(1.0+x*x);
}
//不减少
#pragma omp parallel private(i)
{
int id = omp_get_thread_num();
int numthreads = omp_get_num_threads();
double x;
double partial_sum = 0;
for (i=id;i< num_steps; i+=numthreads){
x = (i+0.5)*step;
partial_sum += + 4.0/(1.0+x*x);
}
#pragma omp critical
sum += partial_sum;
}
我使用 8 个内核运行代码,缩减版本的总时间加倍。什么原因?谢谢。
最佳答案
OpenMP 中的标量缩减通常非常快。在您的案例中观察到的行为是由于两件事以两种不同的方式出错。
在您的第一个代码中,您没有将 x
设为私有(private)。因此,它在线程之间共享,除了得到不正确的结果外,执行还会受到数据共享的影响。每当一个线程写入 x
时,它执行的核心就会向所有其他核心发送一条消息,并使它们使该缓存行的副本无效。当它们中的任何一个稍后写入 x
时,必须重新加载整个缓存行,然后所有其他内核中的缓存行都会失效。等等。这会显着减慢速度。
在您的第二个代码中,您使用了 OpenMP critical
构造。相对于atomic adds,这是一个比较重量级的,通常用来实现最后的reduction。 x86 上的原子添加是使用 LOCK
指令前缀执行的,所有内容都在硬件中实现。另一方面,关键部分是使用互斥锁实现的,需要几条指令和经常繁忙的等待循环。这远低于原子添加的效率。
最后,由于数据共享条件不佳,您的第一个代码速度变慢了。由于使用不正确的同步原语,您的第二个代码速度变慢。碰巧在您的特定系统上,后者的影响没有前者严重,因此您的第二个示例运行得更快。
关于OpenMP 减慢速度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20416277/