代码之家  ›  专栏  ›  技术社区  ›  Dylan Galea

在浮点加法上使用openmp reducation有解决方法吗?

  •  0
  • Dylan Galea  · 技术社区  · 7 年前

    我目前正在使用C++和OpenMP并行化嵌套的for循环。在不讨论程序的实际细节的情况下,我构建了一个关于我正在使用的概念的基本示例:

    float var = 0.f;
    float distance = some float array;
    float temp[] = some float array;
    for(int i=0; i < distance.size; i++){
        \\some work
        for(int j=0; j < temp.size; j++){
            var += temp[i]/distance[j]
        }
    }
    

    我试图用以下方式并行处理上述代码:

    float var = 0.f;
    float distance = some float array;
    float temp[] = some float array;
    #pragma omp parallel for default(shared)
    for(int i=0; i < distance.size; i++){
        \\some work
        #pragma omp parallel for reduction(+:var)
        for(int j=0; j < temp.size; j++){
            var += temp[i]/distance[j]
        }
    }
    

    然后我比较了串行程序输出和并行程序输出,得到了不正确的结果。我知道这主要是因为浮点运算不具有关联性。但是否有任何解决办法可以给出确切的结果?

    1 回复  |  直到 7 年前
        1
  •  2
  •   Gilles MrUser    7 年前

    尽管在某些情况下,浮点运算缺乏关联性可能是一个问题,但此处显示的代码暴露了一个更为重要的问题,您需要首先解决该问题:浮点运算的状态 var 外部循环中的变量。

    确实,因为 var 在 i 循环,即使只在 j 部分 我 循环,它需要以某种方式“私有化”。现在,它需要获得的确切状态取决于您希望它在退出封闭时存储的值。 parallel 区域:

    • 如果你根本不在乎它的价值,只需声明它 private (或者更好,在 平行 区域。
    • 如果您在 我 循环,并且考虑到它累积了一个值的总和,很可能您需要声明它 reduction(+:) 虽然,虽然 lastprivate 也可能是你想要的(没有进一步的细节是不可能说的)
    • 如果 私有的 或 最后一个私有 是你所需要的,但你也需要它的初始值 平行 区域,然后您必须考虑添加 firstprivate 也一样(如果你去的话不需要 reduction 因为它已经被处理过了)

    这就足以解决你的问题了。

    现在,在您的代码片段中,您还平行化了内部循环。对于嵌套的并行性,这通常是一个坏主意。因此,除非您有一个非常令人信服的理由这样做,否则您只需将外部循环并行化,而只保留内部循环,就可能获得更好的性能。这并不意味着内环不会受益于并行化,而是将并行计算内环的几个实例(每个实例都是连续的,但整个过程是并行的)。 去除内部循环的并行化(除了使代码更快)的一个好的副作用是现在所有的聚集在privates中 var 变量的顺序与不并行时的顺序相同。因此,您在外循环中的(假设的)浮点算术问题现在将消失,并且只有当您需要在 平行 地区也许你还会面对他们。

    推荐文章