【问题标题】:OpenMP Nested Loop, what is the code doing?OpenMP 嵌套循环,代码在做什么?
【发布时间】:2012-11-27 05:31:30
【问题描述】:

我在理解 OpenMP 如何处理嵌套循环时遇到问题。请帮忙!

我让以下代码并行运行:

#pragma omp parallel private(i)
{
for(i=0; i<n; i++)
{
    #pragma omp for
    for(j=0; j<n; j++)
    {
        if(asubsref(seed,j) > 0)
            asubsref(bin,j) = asubsref(bin,j) + 1;
    }
    #pragma omp for
    for(j=0; j<n; j++)
        asubsref(seed,j) = asubsref(seed,j) - asubsref(w,i);
}
}

但是,我不太确定这段代码是如何工作的(我只是运气好)。这就是我认为它正在做的事情......

所以for(i=0; i&lt;n; i++) 被分成不同的线程并并行运行。因为i 被声明为private,所以循环的每个实例都是“沙盒”;也就是说,对j 的任何更改都保留在该线程中(至少在所有线程完成之前?)。我很困惑,因为不声明 #pragma omp for 会导致代码中断...我不确定这是为什么。

如果有人能指导我了解这段代码的作用,我将不胜感激!谢谢!

【问题讨论】:

标签: c loops parallel-processing openmp nested-loops


【解决方案1】:

这是一个典型的做法,目的是减少多次进入和退出并行区域的开销。将您问题中的代码与以下等效代码进行比较:

for (i=0; i<n; i++)
{
    #pragma omp parallel for
    for (j=0; j<n; j++)
    {
        if (asubsref(seed,j) > 0)
            asubsref(bin,j) = asubsref(bin,j) + 1;
    }
    #pragma omp parallel for
    for (j=0; j<n; j++)
        asubsref(seed,j) = asubsref(seed,j) - asubsref(w,i);
}

它在i n 上运行外循环。在外循环的每次迭代中,它在j 上运行两个并行循环,将n 迭代拆分到线程中。这里的问题是内部有两个并行区域,每个区域都被激活n 次。这可能会为 n 的某个值间隔增加大量开销(实际间隔将取决于许多因素)。

为了减少开销,我们将整个代码放在一个并行区域内。因此,每个线程将执行外部循环的所有迭代,而内部迭代仍将在线程之间拆分。如果您删除工作共享结构,则内部循环将不会分布在线程之间。相反,每个线程都会执行完整范围的外部 内部迭代,因此例如 asubsref(bin,j) 将增加到 num_threads 次而不是一次(为什么“最多”?提示: 不受保护的并发数据访问)。

大多数时候,在并行结构中运行外循环时,希望不同的线程在相同的迭代中保持滴答作响。这可以通过循环体末尾的屏障来实现:

#pragma omp parallel private(i)
{
    for (i = 0; i < n; i++)
    {
        ...
        #pragma omp barrier
    }
}

在您的情况下,不需要显式屏障,因为 for 工作共享构造在其末尾有一个隐式屏障。

【讨论】:

  • 感谢您的详细解答!我知道#pragma omp for 现在做了什么,但是最外层的for 循环如何在线程之间分配?似乎每个线程都运行外部循环(意味着相同的代码运行不止一次)。除非每个线程只运行for 循环的一次迭代(如#pragma omp for)?我的问题是:为什么我们不需要#pragma omp for 用于最外层的循环(如果我们把它放进去,为什么代码会失败?)
  • 外循环没有被分发。每个线程都运行所有的迭代。也许连续迭代之间存在数据依赖关系。
  • 如果每个线程都运行完整的迭代范围,那不会降低计算机的速度吗?
  • @pauliwago:这会花费一些效率,是的。但是,从 0 迭代到 n 所需的时间大致相同,无论有多少内核并行执行此操作,因此只要您有空闲的容量,它只会在能源使用方面而不是运行时间方面花费您。此外,进入/退出parallel 部分是一项非常昂贵的操作,因此不经常进入/退出一个部分的收益可能会超过为循环控制进行一些冗余计算所带来的任何损失。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-25
  • 1970-01-01
  • 2016-07-27
  • 1970-01-01
  • 2012-11-14
  • 2012-11-01
相关资源
最近更新 更多