【问题标题】:Sequential and parallel versions give different results - Why?顺序和并行版本给出不同的结果 - 为什么?
【发布时间】:2012-04-07 08:06:12
【问题描述】:

我有一个嵌套循环:(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];
        }
    }

但它也没有解决问题。结果仍然不同。

【问题讨论】:

标签: c++ gcc parallel-processing openmp


【解决方案1】:

我对 OpenMP 不是很熟悉,但在我看来,您的计算与顺序无关。即,将内循环中的结果写入L[i][k],其中ik 是内循环的不变量。这意味着在内部循环期间,相同的值会被覆盖k 次,从而导致竞争条件。

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

总而言之,在我看来,如果您想要与顺序执行给出的相同结果,那么内部循环中的计算必须以相同的顺序执行。因此只有外部循环可以并行化。

【讨论】:

  • 我也想过。但是使用这些 pragma 命令,只有外部循环应该被并行化。但显然,线程中正在发生其他事情,因此结果不一样。
【解决方案2】:

在您的并行版本中,您插入了一个不必要的(并且可能有害的)原子指令。一旦您将dummy 声明为归约变量,OpenMP 就会负责停止干扰归约的线程。我认为不必要的指令的主要影响是大大降低你的代码速度。

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

如果您在减少read this 时遇到问题。

【讨论】:

  • 我实际上希望内部循环在每个线程中按顺序运行。我现在假设内部循环也是分布式的 - 否则我不会遇到这些问题。我稍微修改了代码。我进行了编辑,以便您可以看到修改。
【解决方案3】:

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

澄清: 循环变量n 应该在omp pragma 中声明,因为它应该是线程特定的,例如for (int n = 0;.....)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-10-27
    • 2023-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-29
    • 2021-12-07
    • 2020-10-15
    相关资源
    最近更新 更多