连续和并行版本会产生不同的结果 - 为什么?

问题描述:

我有一个嵌套的循环:(L和A完全定义输入)连续和并行版本会产生不同的结果 - 为什么?

#pragma omp parallel for schedule(guided) shared(L,A) \ 
    reduction(+:dummy) 
    for (i=k+1;i<row;i++){ 
      for (n=0;n<k;n++){ 
       #pragma omp atomic 
       dummy += L[i][n]*L[k][n]; 
       L[i][k] = (A[i][k] - dummy)/L[k][k]; 
      } 
      dummy = 0; 
    } 

而其串行版本:

for (i=k+1;i<row;i++){ 
      for (n=0;n<k;n++){ 
       dummy += L[i][n]*L[k][n]; 
       L[i][k] = (A[i][k] - dummy)/L[k][k]; 
      } 
      dummy = 0; 
    } 

他们都得到不同的结果。并行版本比顺序版本慢得多。

什么可能导致问题?

编辑:

为了摆脱引起的原子指令的问题,我修改了代码如下:

#pragma omp parallel for schedule(guided) shared(L,A) \ 
    private(i) 
    for (i=k+1;i<row;i++){ 
     double dummyy = 0; 
     for (n=0;n<k;n++){ 
      dummyy += L[i][n]*L[k][n]; 
      L[i][k] = (A[i][k] - dummyy)/L[k][k]; 
     } 
    } 

但它也没有工作出了问题。结果仍然不同。

+0

如果您在浮点数操作,请阅读此http://计算器.com/a/8991640/893693 – inf 2012-04-07 08:21:46

结果的差异来自线程间共享的内部循环变量n,因为它是在omp编译指示之外定义的。

澄清: 循环变量n应OMP编译内部声明,因为它应该是线程专用的,例如for (int n = 0;.....)

+0

完全解决了我的问题。谢谢! – 2012-04-07 10:54:20

+0

@Lubo,那么正确的方法是什么? – 2013-09-28 13:12:20

我对OpenMP并不是很熟悉,但在我看来,您的计算并不依赖于顺序。也就是说,内循环中的结果写入L[i][k],其中ik是内循环的不变量。这意味着在内循环期间相同的值被覆盖k次,导致竞争条件。

此外,dummy似乎在不同的线程之间共享,所以也可能存在竞争条件,除非您的编译指示参数以某种方式阻止它。

总而言之,对于我来说,如果您希望获得与顺序执行相同的结果,则内部循环中的计算必须以相同的顺序执行。因此只有外部环路可以并行化。

+0

我也考虑过这个问题。但是使用这些编译指令,只有外部循环应该被并行化。但显然,线程内部正在发生其他事情,所以结果并不相同。 – 2012-04-07 08:45:13

在您的并行版本中,您插入了不必要的(可能有害的)原子指令。一旦你声明dummy是一个缩减变量,OpenMP负责停止干扰缩减的线程。我认为这个不必要的指令的主要影响是减慢你的代码,很多。

我看到你有另一个解决你的结果错误的答案。但我注意到,在每个外循环迭代结束时,您似乎将dummy设置为0,如果您尝试将它用作某种累加器,这似乎很奇怪,这就是还原子句所暗示的内容。也许你想在内循环中减少到dummy

如果您在还原时遇到问题read this

+0

我实际上想要内循环在每个线程中顺序运行。我现在假设内部循环也是分布式的 - 否则我不会遇到这些问题。 我稍微修改了代码。我编辑过,以便您可以看到修改。 – 2012-04-07 08:50:14