【问题标题】:Parallelization of dependent nested loops依赖嵌套循环的并行化
【发布时间】:2021-07-30 02:32:15
【问题描述】:

我的目标是在 C++ 上计算一个简单的 N 体程序,并且我正在使用 OpenMP 来加快计算速度。在某些时候,我的嵌套循环看起来像这样:

int N;
double* S          = new double[N];
double* Weight     = new double[N];
double* Coordinate = new double[N];
 ...

#pragma omp parallel for
for (int i = 0; i < N; ++i)
{
   for (int j = 0; j < i; ++j)
   {
       double K = Coordinate[i] - Coordinate[j];
       S[i]    += K*Weight[j];
       S[j]    -= K*Weight[i];
   }
}

这里的问题是我在删除#pragma 时没有得到完全相同的结果......我猜这与第二个循环依赖于整数 i 的事实有关,但我不看看如何解决这个问题

【问题讨论】:

  • 如果您使用collapse 子句,则依赖内循环只会在正确结果方面成为问题。但是,如果 OpenMP 默认使用 static 调度,它可能会影响性能,因为不同的线程可能有非常不同的工作负载。因此,您应该确保使用 dynamic 调度,例如带有schedule(dynamic) 子句。在this question下面有深入的解释。

标签: c++ loops parallel-processing openmp


【解决方案1】:

问题是在更新S[i]S[j] 期间存在数据竞争。不同的线程可能同时读取/写入数组的同一元素,因此它应该是一个原子操作(您必须添加#pragma omp atomic)以避免数据竞争并确保内存一致性:

for (int j = 0; j < i; ++j)
{
    double K = Coordinate[i] - Coordinate[j];
    #pragma omp atomic
    S[i]    += K*Weight[j];    
    #pragma omp atomic
    S[j]    -= K*Weight[i];
}

【讨论】:

  • 非常感谢,它确实有助于减少错误。它们仍然是无与伦比的循环和并行循环之间的 1e-15 相对误差,但我认为它与浮动加法误差有关,而不是并行化。
  • 不客气。这个小误差并不奇怪,因为相加的顺序不同,所以舍入误差也不同。
  • 如果您对舍入误差的细节感兴趣,请阅读:docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-12
  • 2020-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多