哪种方法应该更快? 第一种方法是增加一个变量用于减少:
#pragma omp parallel private(seed, x, y, i) reduction (+:counter)
{
seed = 25234 + 17 * omp_get_thread_num();
nproc = omp_get_thread_num();
#pragma omp parallel for
for(i=0; i<prec/8; i++){
x = (double)rand_r(&seed) / RAND_MAX;
y = (double)rand_r(&seed) / RAND_MAX;
if(x*x+y*y<1){
counter++;
}
}
第二个是每个进程使用增量变量表,最后,该表中元素的总和是结果:
#pragma omp parallel private(seed, x, y, i , nproc)
{
seed = 25234 + 17 * omp_get_thread_num();
nproc = omp_get_thread_num();
#pragma omp parallel for
for(i=0; i<prec/8; i++){
x = (double)rand_r(&seed) / RAND_MAX;
y = (double)rand_r(&seed) / RAND_MAX;
if(x*x+y*y<1){
counter[nproc]++;
}
}
}
double time = omp_get_wtime() - start_time;
int sum=0;
for(int i=0; i<8; i++){
sum+=counter[i];
}
理论上,第二种方式应该更快,因为进程不共享一个变量,但每个进程都有自己的变量。 但是当我计算执行时间时:
first approach: 3.72423 [s]
second approach: 8.94479[s]
我认为错了或我在代码中做错了什么?
答案 0 :(得分:4)
在第二种方法中,您是false sharing的受害者。这是一个有趣的article from Intel。
当不同处理器上的线程修改时,会发生错误共享 驻留在同一缓存行上的变量。这使得无效 缓存行并强制执行内存更新以保持缓存一致性。
如果两个处理器在同一存储器中对独立数据进行操作 地址区域可存储在单行中,缓存一致性 系统中的机制可能会迫使整条线路穿过公交车或 与每次数据写入互连,另外还会导致内存停顿 浪费系统带宽
直观地说,我不认为第一种方法应该更慢 您确实在每个线程上创建了一个私有副本,然后将最终结果应用于全局变量。行为在某种程度上与您的共享阵列相同,但这里的问题是即使您的访问是独立的,您也会得到错误的共享。