我在理解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<n; i++)
被拆分为不同的线程并且并行运行。因为i
被声明为private
,所以循环的每个实例都是“沙盒”;也就是说,对j
的任何更改都保留在该线程中(至少在完成所有线程之前?)。我很困惑,因为没有声明#pragma omp for
导致代码破坏......我不确定为什么会这样。
如果有人能指导我完成这段代码的工作,我会非常感激!谢谢!
答案 0 :(得分:2)
这是人们通常所做的,以减少多次进入的开销并进出并行区域。将您问题中的代码与以下等效代码进行比较:
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
次,而不是仅增加一次(为什么&# 34;最多&#34;?提示:不受保护的并发数据访问)。
大多数情况下,当一个人在并行构造中运行外部循环时,人们希望不同的线程在相同的迭代中保持滴答作响。这可以通过循环体末端的屏障来实现:
#pragma omp parallel private(i)
{
for (i = 0; i < n; i++)
{
...
#pragma omp barrier
}
}
在您的情况下,由于for
工作共享结构在其末尾具有隐式屏障,因此不需要显式屏障。