我面临着在一个更大的三维arrays内并行化一个algorithm,该algorithm在其串行实现中检查arrays位置的立方体的六个面。 (也就是说,select一个数组元素,然后定义一个围绕x,y和z的数组元素“n”个元素的立方体或长方体,并以数组边界为界。
每个工作单元看起来像这样(Fortran伪代码;串行algorithm在Fortran中):
do n1=nlo,nhi do o1=olo,ohi if (somecondition(n1,o1) .eq. .TRUE.) then retval =.TRUE. RETURN endif end do end do
或C伪代码:
for (n1=nlo,n1<=nhi,n++) { for (o1=olo,o1<=ohi,o++) { if(somecondition(n1,o1)!=0) { return (bool)true; } } }
总algorithm中有6个工作单元,其中'lo'和'hi'值一般在10到300之间。
Multiprocessing =多个进程正在运行?
英特尔指令的LOCK前缀。 有什么意义?
Bash:在多个核心上运行相同的程序
那里有没有很好的并发/并行书籍不关注Java?
Rmpi:不能使用MPI_Comm_spawn API
我认为最好的做法是安排6个或更多的执行线程,如果cpu数量不是很多,理想情况下并行执行循环,则循环法与目标序列algorithm相同: somecondition()变为True ,所有线程之间的执行必须立即停止,并在共享位置设置一个True值。
在Windows编译器中存在哪些技术来促进并行化这样的任务? 显然,我需要一个等待信号量或工作线程完成的主线程,所以需要嵌套和信号传递,但是我对OpenMP的使用经验是在这里介绍的。
OpenMP中有消息传递机制吗?
编辑:如果“nlo”和“nhi”或“olo”和“ohi”之间的最大差异是8到10,那么这个嵌套循环不会超过64到100次迭代,并且不会超过384到600次迭代为六个工作单位在一起。 基于此,是否值得并行?
在R中的并行处理有限
C编程逻辑 – 试图完成线程(fork)并且不会离开不可用的进程
如何等待fork()调用的所有subprocess完成?
如何find关于我的cpu的并行架构的信息?
如何批量使用Image Magic批量转换多个子目录中的图像
一种可能性是使用OpenMP来并行化6个循环 – 声明logical :: array(6) ,允许每个循环运行完成,然后retval = any(array) 。 然后你可以检查这个值并返回到并行化的循环之外。 如果你这样做,将一个schedule(dynamic)添加到并行do语句。 或者,有一个单独的!$omp parallel然后放!$omp do schedule(dynamic) … !$omp end do Nowait在6个循环的每一个周围都!$omp end do Nowait 。
或者,你可以遵循@MSB的好建议,并在整个数组上并行化最外层的循环。 这里的问题是你不能在一个并行循环中有一个RETURN – 所以要标记第二个最外层的循环(并行部分中最大的一个),并且EXIT那个循环 –
retval = .FALSE. !$omp parallel do default(private) shared(BIGARRAY,retval) schedule(dynamic,1) do k=1,NN if(.not. retval) then outer2: do j=1,NN do i=1,NN ! --- your loop #1 do n1=nlo,ohi if (somecondition(BIGARRAY(i,j,k),n1,o1)) then retval =.TRUE. exit outer2 endif end do end do ! --- your loops #2 ... #6 go here end do end do outer2 end if end do !$omp end parallel do
if语句是假定你需要知道在大数组中是否至少有一个这样的元素。 如果您需要为每个元素指定条件,则可以类似地添加一个虚拟循环出口或跳转,跳过该元素的其余处理。 再次使用时间表(动态)或时间表(指导)。]
作为一个单独的观点,你可能也想要检查是否是一个好主意,通过一些更大的步骤(取决于float大小)通过最内层循环,计算每个迭代的逻辑的向量,然后汇总结果,例如。 if(count(somecondition(x(o1:o1+step,k)))>0) ; 在这种情况下,编译器可能能够矢量化somecondition 。
将数组元素上的循环并行化并将该算法串联起来,多个线程在不同的数组元素上运行该算法会更好吗? 我从你的评论中思考这个问题:“时间消耗来自这样一个事实:阵列中的每个元素都必须像这样测试,阵列通常有四百万到两千万个元素。 实现数组元素并行化的设计在数字线程方面也是灵活的。 除非有一个原因,数组元素必须按照某种顺序检查?
看起来,你给我们展示的那部分并不需要那么长的时间来执行,所以通过并行执行并行可能会花费更少的时间,这可能并不容易…多线程总会有一些开销,如果没有并行代码可能不会更快。
我相信你可以用OpenMP 3中引入的任务构造完成你想要的任务; 英特尔Fortran支持在OpenMP中分配任务。 我不经常使用任务,所以我不会为您提供任何不可靠的伪代码。
你已经提到了一个明显的方法,一旦任何线程发现结束条件就立即停止所有线程:每个检查一个共享变量给出结束条件的状态,从而确定是否突破循环。 显然这是一个开销,所以如果你决定采取这种方法,我会建议一些事情:
使用原子来检查结束条件,这避免了昂贵的内存刷新,因为只是有问题的变量被刷新。 移到OpenMP 3.1,支持一些新的原子操作。
不经常检查,也许每个外迭代一次。 你只应该平行大案例来克服多线程的开销。
这个是可选的,但你可以尝试添加编译器提示,例如,如果你希望大多数情况下某个条件是错误的,编译器会相应地优化代码。
另一种(比较脏)的方法是为每个线程的循环范围使用共享变量,也许使用共享数组,其中索引n是线程n。 当一个线程发现结束条件时,它会更改所有其他线程的循环范围,以使其停止。 你需要适当的内存同步。 基本上,开销已经从检查虚拟变量转移到同步/检查循环条件。 再次可能不太经常这样做,所以也许使用共享外部循环变量和私有内部循环变量。
在另一个说明中,这让我想起了经典的轮询与中断问题。 不幸的是,我不认为OpenMP支持可以向每个线程发送某种终止信号的中断。
有黑客的解决方法,比如使用一个子进程来处理这个并行的工作,并调用操作系统调度器来模拟中断,但是要正确地使用这些代码是非常棘手的,并且会让你的代码变得不可移植。
更新回应评论:
尝试这样的事情:
char shared_var = 0; #pragma omp parallel { //you should have some method for setting loop ranges for each thread for (n1=nlo; n1<=nhi; n1++) { for (o1=olo; o1<=ohi; o1++) { if (somecondition(n1,o1)!=0) { #pragma omp atomic write shared_var = 1; //done marker,this will also trigger the other break below break; //Could instead use goto to break out of both loops in 1 go } } #pragma omp atomic read private_var = shared_var; if (private_var!=0) break; } }
一个合适的并行方法可能是,让每个工作人员检查整个问题的一部分,正如在序列情况下一样,并使用一个本地(非共享)变量作为结果(retval)。 最后,把这些局部变量的所有工作人员减少到共同的总体结果。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。