用于嵌套 for 循环的 OpenMP?

Posted

技术标签:

【中文标题】用于嵌套 for 循环的 OpenMP?【英文标题】:OpenMP for nested for loops? 【发布时间】:2010-08-22 23:06:14 【问题描述】:

我试图在我的项目中使用 OpenMP,该项目在模拟中包含 N 个代理。每个代理都有一个位置向量。在我的程序中,我执行以下操作:

for(int i=0;i<agents.size();i++)
 for(int j=0;j<agents.size();j++)
   if(i==j) continue;
   if(distance_between(i,j)<10)
     //do a lot of calculations for interaction between i and j,
     //and a bunch of changes to variables of the Agents stored in the list
   
 

我可以简单地在第一个循环前面添加“#pragma omp parallel for”来分配工作吗?如果我这样做,我的程序会运行得更快,但我担心它所做的计算可能不准确。

这些计算的顺序无关紧要,只要处理每个 i,j 对,并且在最内层循环内定义的变量之外没有任何变量,并且我的 Agents 类中的变量曾经更改过(只读) .

我不是系统专家,我很难理解 OpenMP 的内部工作原理,并且对此有点怀疑。感谢您对此的任何帮助!

【问题讨论】:

你必须确保你的 for 循环不会阻碍并行化(例如,数据依赖) 【参考方案1】:

是的,添加编译指示是正确的。内存被所有线程隐式共享。但这并不意味着它会更快地工作。有多个问题需要考虑:

您的系统有多少个处理器? 您使用整数还是浮点数?对于整数,顺序无关紧要,但对于浮点则不是这样 哪些变量只能由最内层循环访问?您可以将它们声明为私有以获得更好的性能。

【讨论】:

在***.com/questions/2100490/…,您可以找到一些浮点问题的示例。使用多线程时,问题3(四舍五入)会影响结果(差异可能很小,但这取决于算法)【参考方案2】:

我可以简单地在第一个循环前面添加“#pragma omp parallel for”来分配工作吗?

这取决于你在并行部分会做什么。为了获得更好的性能,您可能会更改并行代码的算法,而不仅仅是将#pragma omp parallel 放入您的序列代码中。请记住,并行编程的关键是共享变量。在某些情况下,使用序列代码比使用并行代码更好。

如果我这样做,我的程序会运行得更快,但我担心它所做的计算可能不准确。

确实,您必须确保代码中没有竞争条件才能获得正确的计算结果。

【讨论】:

【参考方案3】:

确保影响相同数据的交互 i,jj,i 不会导致数据争用。您可以仔细调整工作的分布,或在必要时使用omp criticalomp atomic 构造。

除此之外,仅通过在外循环上使用omp parallel for 构造来使您的代码运行得更快完全没有问题。请记住,如果您的处理器具有的处理单元(核心、硬件线程等)的数量,或者如果您使用的是 ccNUMA 机器,那么做一些额外的事情可能是一个好主意,因为您的代码的可扩展性将做得不够好。

最简单的改进是将collapse(2) 添加到您的omp for 子句中。这将告诉 OpenMP 您希望完全分发这两个循环的迭代。

#pragma omp parallel for collapse(2)
for(int i=0;i<agents.size();i++)
 for(int j=0;j<agents.size();j++)
   if(i==j) continue;
   if(distance_between(i,j)<10)
     //do a lot of calculations for interaction between i and j,
     //and a bunch of changes to variables of the Agents stored in the list
   
  

一旦您遇到大量粒子(或您所称的代理),根据它们的位置对所有粒子进行排序可能是明智之举。这将导致最内层循环内的if 条件具有更稳定的行为,从而可以更好地预测分支(请参阅why is it faster to process a sorted array)。

此外,如果将几何空间划分为 bin,则可以完全删除分支。这是因为您确切地知道非相邻存储桶距离太远而无法成功。

这类问题众所周知,您可能已经知道,它们被称为n-body problems。存储桶优化版本称为Barnes-Hut simulation,尽管您可能会发现其他方法工作得更快(虽然更难并行化,但大多数时候仍然更有效),例如Fast Multipole Method,它或多或少包括减少通过在同一步骤中解决 i,jj,i 两个交互的计算次数。

【讨论】:

以上是关于用于嵌套 for 循环的 OpenMP?的主要内容,如果未能解决你的问题,请参考以下文章

OpenMP 如何处理嵌套循环?

在 OpenMP 中并行化嵌套循环并使用更多线程执行内部循环

使用 OpenMP 在 C、C++ 中并行化嵌套 for 循环的几种方法之间的区别

哪个库用于迭代 1M*1k 次的并行 for 循环,OpenMP 或 boost::thread?

嵌套循环的 OpenMP SIMD 矢量化

OpenMP 矩阵乘法嵌套循环