有懂并行MPI的吗?我有几个简单的小魔术问题...

只需一步,快速开始
扫一扫,访问微社区
后使用快捷导航没有帐号?
查看: 5704|回复: 16
大家做lbm时有自己编程并行计算的吗,具体怎么实现?
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
才可以下载或查看,没有帐号?
大家做lbm时有自己编程并行计算的吗,具体怎么实现?
回复 1# matrixmess 的帖子
如果没有局部网格优化的话,可以参考这篇文章:
Direct Numerical Simulation of Particulate Flows on 294 912 Processor Cores
整天听LBM并行的优点,从来没尝试并行过,多核并行也没考虑过。算的东西机时还真不少,惭愧啊
我在做LBM的并行,3D多相流的。并行没有LBM吹得那么牛,什么自身的碰撞、stream就自动并行啦!其实跟一般的FVM并行一样的,比较特别的就是数据swap的时候需要考虑沿edge的临近的processors的交换。还有就是stream完后要完成一步数据平衡变量的update,其他的都一般了,没有什么神秘特别的地方。会做FVM并行就能做LBM的并行。
用OpenMP很简单,并行度受CPU核数限制。
用MPI组网或上超算挺好,编程复杂一些,受节点间数据传输的限制。
用CUDA也挺好,编程复杂。
可以先用openMP,现在12核的电脑都出来了,对于一般规模的,足够了
原帖由 particlecfd 于
16:37 发表
我在做LBM的并行,3D多相流的。并行没有LBM吹得那么牛,什么自身的碰撞、stream就自动并行啦!其实跟一般的FVM并行一样的,比较特别的就是数据swap的时候需要考虑沿edge的临近的processors的交换。还有就是stream完后 ...
如果你是区域分裂,当然LBM和FVM的并行思路是一样的。但标准LB的碰撞在当地,而迁移也涉及相邻有限节点,且不需要求解poison方程啥的,因而采用迁移碰撞的LB的scalability会比FVM好很多。
我做湍流,用基于FVM的LBM(非结构网格)以及标准LBM,都是2048个处理器,后者计算速率是前者的10倍以上,差别就在于网格以及数据交换。同时我也用过FVM做,FVM的scalability更差。
当然,我说的都是非定常问题。
原帖由 ywang 于
08:22 发表
如果你是区域分裂,当然LBM和FVM的并行思路是一样的。但标准LB的碰撞在当地,而迁移也涉及相邻有限节点,且不需要求解poison方程啥的,因而采用迁移碰撞的LB的scalability会比FVM好很多。
我做湍流,用基于FVM的 ...
FVM的scalability很好,我做的1个亿的非结构化网格,8192个processors一点问题都没有,不知到你为什么会说FVM的scalability有问题。可能是你用的方法有问题。
我并没有说LBM的scalability会差,不过它的MPI并行真的没有比FVM复杂很多,都是一个思路。所以做过FVM的MPI,再做LBM的MPI不是很难,没有什么本质的区别,没有那么神秘啦!
原帖由 particlecfd 于
16:42 发表
FVM的scalability很好,我做的1个亿的非结构化网格,8192个processors一点问题都没有,不知到你为什么会说FVM的scalability有问题。可能是你用的方法有问题。
我并没有说LBM的scalability会差,不过它的MPI并行真 ...
FVM我是用的OpenFOAM里面基于piso的LES求解器,十来个处理器下并行效率就低了,我也挺奇怪这一点;基于FVM的LBM代码是自己搞的,scalability可以,但计算速率不如标准LBM。
另外,好像这个帖子里没人说LBM的并行多么神秘,呵呵。我前面说过,如果用区域分裂,LB的并行和FV一个思路,但由于LB的特性,那么处理起来会更简单。
我目前,LBM,一千七百万网格,在用16384个处理器跑。因为网格量并不大,所以再往上增多处理器就不太划算了,呵呵。
[ 本帖最后由 ywang 于
07:02 编辑 ]
原帖由 ywang 于
07:00 发表
FVM我是用的OpenFOAM里面基于piso的LES求解器,十来个处理器下并行效率就低了,我也挺奇怪这一点;基于FVM的LBM代码是自己搞的,scalability可以,但计算速率不如标准LBM。
另外,好像这个帖子里没人说LBM的并行 ...
OpenFOAM提供了好几种并行方法,如果用那个simple的方法(就是简单沿xyz方向给定要分配的CPU个数),对于complex geometry很难有好的scalability。
LBM的并行的神秘性不是从你哪里听到的,是我以前的一个同事说的,尽管他实现不了LBM的并行,还是在那里吹嘘什么LBM自身是就并行了的啥啥的,把LBM说的神的不得了。反正当时是唬了不少人,包括我以前的老板。
多相流LBM因为要考虑很多偏导数项,不用FVM很难实现比如表面张力,两相之间的相互作用力等的计算。如果不用FVM,LBM的并行思路还是跟一般的FVM一样,只是不要数据交换做导数计算,只要平衡态变量的数据传递即可,所以会比FVM要快。不过这种LBM只是应付单相流还可以。我们开发的这种单相流并行LBM在1个亿左右的网格,8192个processors上的并行效率达到90%以上。
FVM、LBM还有FDM、FEM等的MPI并行都是一个思路,只要做过其中的一个,其他的只要照猫画虎就可以搞定,哪个都不神秘。
lbm和fvm我都做过一点。 两者并行的思想是一样的, 不管你是粒子碰撞还是用求解散度、梯度和拉普拉斯。 个人感觉,lbm之所以scalability好,并不是由于粒子碰撞,而是不用求解代数方程组。他是一种显式的时间推进,各个节点彼此影响较小,每个时间步骤粒子的对流只需要做一次,因此只需要交换一次。而代数方程组的求解需要全场的统一求解,每次迭代步都需要交换信息。交换信息量肯定要比lbm多。如果你用显式的时间推进算法求解fvm离散后的方程,每个时间步骤交换一次,仍然可以实现scalability很好。 并行性和你选择的代数方程求解器也有关系的。如果采用代数多重网格做预条件,而采用共轭梯度求解方法,并行性估计也应该很好的,因为他求解代数方程迭代步比较少,因此信息交换少。
对于不可压缩问题fvm方法分离求解而言,由于simple/piso算法的关系,压力泊松问题通常是不可避免的,因此代数方程仍然需要求解的,因此并行性的scalability不如显示推进的lbm好。 而对于可压缩问题,显式时间推进fvm仍然可以做到很好的并行。
ps 木头:我做的那个fvmlbm之所以比标准的lbm效率低,和fvm方法无关,是因为我写非平衡外推边界条件的时候,为了方便将梯度计算搞成全场的了,而且每个时间步长只更新一次,边界自然延迟了,求解过程应该每次用到边界都根据当前情况更新的。改成局部的梯度计算自然效率就可以上来。 而且,fvm中耗时部分最大的是代数方程求解,梯度求解时占第二位的。fvmlbm也是一种显式推进,scalablity当然也可以啊。不需要交换过多信息嘛。
lbm方法不管是标准的还是基于fvm的,他都采用时间推进方法来做流动。 由于粒子碰撞是局部的,所以在求解椭圆型问题上,比如:不可压缩问题或者稳态问题时,fvm的效率应该比lbm高一些,因为lbm的影响并不能马上传到全场。 可以找个顶盖或者管流算算。个人感觉。
[ 本帖最后由 su_junwei 于
22:50 编辑 ]
回复 11# su_junwei 的帖子
理论而言,LBM压力场不可能一下子传到全场,这违背弱可压性质。FVM用来求解LBM不可能比标准的LBM框架快,FVM直接求解代数方程组之非常致命的。同时,尽管LBM是简单的显式求解,但它是具有高的精度。对于非稳态问题,LBM的效率比NSE高阶方法的求解器快。用FVM来求解LBM,这就显然会非常慢,梯度操作运算,就是个弱点,即便采用显式。如果再求解代数方程组,就更要命。要提高精度再使用高阶框架,那就更慢。3D就更不用说了。
原帖由 su_junwei 于
22:46 发表
lbm和fvm我都做过一点。 两者并行的思想是一样的, 不管你是粒子碰撞还是用求解散度、梯度和拉普拉斯。 个人感觉,lbm之所以scalability好,并不是由于粒子碰撞,而是不用求解代数方程组。他是一种显式的时间推进,各 ...
呵呵,如果基于区域分裂,fvm,fdm,lbm等等都一样,这是肯定的。我以前也在一个CFD公司也参与过FVM代码的并行化处理,所以算起来两方面都了解一点,思路当然都没啥差别,呵呵。但如果在向量计算机上,似乎lb的并行就会更好一些,这个我不懂,仅仅有这方面的印象。另外,我测OpenFOAM的LES求解器的时候,是一个很简单的长方体模型,而且多种并行方式都测试过,呵呵。
军伟,lbm是在求解代数方程组的,呵呵。lbm的显式时间推进就是显式求解常系数代数方程组,迁移就来自于空间一阶迎风离散。lb算稳态问题,确实没fvm之类的快,这方面有一些文献可以看看。但对于非稳态问题,且涉及大规模计算的时候,lbm在计算效率方面的优势就凸显出来了。另外,咱们最开始搞的那个版本的fvmlbm慢并不是主要因为边界处理。我对每一部分的效率测试过。在我后来改进的版本里,即使只计算边界梯度信息,提速不到10%;而且有的边界处理不需要梯度信息。最耗时的其实是对流项,按照最初的处理方式,首先离散方向就增加了几倍。改成Succi他们的法子会好一些。我后来还修改了隐式显式的那些格式,加了外力模型。结论是,即使使用最高效的隐式显式格式,最省时的空间离散,计算效率也不太符合我需求,而且数值粘性比我预期的大(OF里面能用的都尝试过,包括不同权系数的混合格式,算湍流,高阶不稳定,低阶又粘性大)。呵呵,所以就没继续搞了。我们还尝试了加LES,呵呵。
[ 本帖最后由 ywang 于
02:05 编辑 ]
哈哈,受教了。
[ 本帖最后由 su_junwei 于
10:35 编辑 ]
原帖由 ywang 于
05:58 发表
呵呵,如果基于区域分裂,fvm,fdm,lbm等等都一样,这是肯定的。我以前也在一个CFD公司也参与过FVM代码的并行化处理,所以算起来两方面都了解一点,思路当然都没啥差别,呵呵。但如果在向量计算机上,似乎lb的并行 ...
是不是在选择不同的方法的时候,那些权系数都取1了。如果OpenFOAM的所有并行方法都不行,那对于研究者来说是亮点,好事呀。这样你可以把自己的方法加进去,如果提高了,除了发文章以外,肯定还会有用户感兴趣,到时候大把的银子入帐 。
不过最好先仔细研究一下是不是自己选择的方法和运用方式有问题,还有运行OpenFOAM的平台是不是有问题。我们用的OpenFOAM波音737整机的模拟(5千万个非结构化网格)的scalability没有问题,不过湍流模型用的是RANS。
[ 本帖最后由 particlecfd 于
14:01 编辑 ]
Powered by
   大数据并行计算利器之MPI/OpenMP - 文章 - 伯乐在线
& 大数据并行计算利器之MPI/OpenMP
图像连通域标记算法是从一幅栅格图像(通常为二值图像)中,将互相邻接(4邻接或8邻接)的具有非背景值的像素集合提取出来,为不同的连通域填入数字标记,并且统计连通域的数目。通过对栅格图像中进行连通域标记,可用于静态地分析各连通域斑块的分布,或动态地分析这些斑块随时间的集聚或离散,是图像处理非常基础的算法。目前常用的连通域标记算法有1)扫描法(二次扫描法、单向反复扫描法等)、2)线标记法、3)区域增长法。二次扫描法由于简单通用而被广泛使用!
图1 连通域标记示意图
随着所要处理的数据量越来越大,使用传统的串行计算技术的连通域标记算法运行时间过长,难以满足实际应用的效率需求。随着并行计算技术的发展,利用不同的编程模型,许多数据密集型的计算任务可以被同时分配给单机多核或多机多处理器进行并行处理,从而有可能大幅度缩减计算时间。目前在集群计算领域广泛使用MPI来进行并行化,在单机领域广泛使用OpenMP进行化,本文针对基于等价对的二值图像连通域标记算法的进行了并行化设计,利用不同的并行编程模型分别实现了不同的并行算法,并通过实验对利用不同并行编程模型所实现的连通域标记算法进行了性能对比分析。
2 二次扫描串行算法思想
顾名思义,二次扫描串行算法步骤包含两部分。
2.1 第一次扫描
b)等价关系建立
2.2 第二次扫描
利用并查集链表进行标记更新。
3 并行化策略
3.1 数据划分并行策略
二次扫描的串行算法中,非直接相邻的各像元数据之间是无关的,将图像分割为数据块后,对于各个数据块之间的主体运算也是独立无关的,可并行性较高,因此可通过对图像进行分块来加快计算时间、提高计算效率。
3.2 并行算法步骤
a)各个进程分别使用串行算法计算
b)各个进程将各块的标记值唯一化
c)生成等价对数组
d)主进程生成全局并查集链表
将1到n-1进程中比较获得的等价对数组统一发送给0进程,0进程生成并查集链表。
e)广播全局并查集链表,各进程更改标记值
主进程广播全局并查集链表,各进程接收后更新标记值。
4 程序实现
并行算法详细流程图。
MPI版本和OpenMP版本的并行算法。
5 测试准备
5.1 实验目的
a)正确性;
b)效率:测试不同连通域数目的数据、不同机器环境(单机和集群)、不同并行编程模型(MPI和OpenMP)对二次扫描并行算法效率的影响。
5.2 测试环境
CPU:两颗Intel(R) Quad Core E5645 Xeon(R) CPU,共12核;
内存:80GB ;操作系统:Linux CentOS 64位。
b)高性能集群(4个计算节点,1个存储节点)
CPU:两颗Intel(R) Quad Core E5645 Xeon(R) CPU,共12核;
内存:32GB;操作系统:Linux CentOS 64位;
节点间文件系统:Network File System (NFS)。
c)测试数据
两个相同数据量( 1 )的二值栅格图像,一个连通域为3个(简单图),一个连通域为10433个(复杂图)
效率测试结果
6.1 结果1:复杂图和简单图的运行时间
6.2 为什么复杂图计算时间更长?
6.3 结果2:单节点环境下,复杂图和简单图的加速比
6.4 问题1:为什么会出现超线性加速比?
原因:并查集链表的影响。
连通域标记算法很多时间用于对并查集链表进行大量查询和插入操作。
6.5 问题2:为什么复杂图比简单图加速比高?
6.6 结果3:集群环境下,复杂图和简单图的加速比
6.7 问题:为什么进程数超过12时,复杂图加速比不再上升,而简单图加速比继续上升?
6.8 结果4:OpenMP版本与MPI版本的比较?
6.9问题:为什么MPI 1个进程比OpenMP 1个线程更高效?
6.10 OpenMP开辟线程的开销?
6.11 OpenMP编译制导语句会影响编译结果?
OpenMP编译制导语句会影响编译结果,这也可以解释单线程OpenMP程序比串行程序慢这一现象。
连通域标记算法的并行化研究,马益杭、占利军、谢传节、秦承志,《地理与地理信息科学》
打赏支持我写出更多好文章,谢谢!
打赏支持我写出更多好文章,谢谢!
关于作者:
可能感兴趣的话题
关于伯乐在线博客
在这个信息爆炸的时代,人们已然被大量、快速并且简短的信息所包围。然而,我们相信:过多“快餐”式的阅读只会令人“虚胖”,缺乏实质的内涵。伯乐在线内容团队正试图以我们微薄的力量,把优秀的原创文章和译文分享给读者,为“快餐”添加一些“营养”元素。
新浪微博:
推荐微信号
(加好友请注明来意)
– 好的话题、有启发的回复、值得信赖的圈子
– 分享和发现有价值的内容与观点
– 为IT单身男女服务的征婚传播平台
– 优秀的工具资源导航
– 翻译传播优秀的外文文章
– 国内外的精选文章
– UI,网页,交互和用户体验
– 专注iOS技术分享
– 专注Android技术分享
– JavaScript, HTML5, CSS
– 专注Java技术分享
– 专注Python技术分享
& 2017 伯乐在线中国领先的IT技术网站
51CTO旗下网站
Python多进程并行编程实践: mpi4py 的使用
在高性能计算的项目中我们通常都会使用效率更高的编译型的语言例如C、C++、Fortran等,但是由于Python的灵活性和易用性使得它在发展和验证算法方面备受人们的青睐于是在高性能计算领域也经常能看到Python的身影了。本文简单介绍在Python环境下使用MPI接口在集群上进行多进程并行计算的方法。
作者:佚名来源:Python开发者| 15:20
在高性能计算的项目中我们通常都会使用效率更高的编译型的语言例如C、C++、Fortran等,但是由于Python的灵活性和易用性使得它在发展和验证算法方面备受人们的青睐于是在高性能计算领域也经常能看到Python的身影了。本文简单介绍在Python环境下使用MPI接口在集群上进行多进程并行计算的方法。
MPI(Message Passing Interface)
这里我先对MPI进行一下简单的介绍,MPI的全称是Message Passing Interface,即消息传递接口。
它并不是一门语言,而是一个库,我们可以用Fortran、C、C++结合MPI提供的接口来将串行的程序进行并行化处理,也可以认为Fortran+MPI或者C+MPI是一种再原来串行语言的基础上扩展出来的并行语言。
它是一种标准而不是特定的实现,具体的可以有很多不同的实现,例如MPICH、OpenMPI等。
它是一种消息传递编程模型,顾名思义,它就是专门服务于进程间通信的。
MPI的工作方式很好理解,我们可以同时启动一组进程,在同一个通信域中不同的进程都有不同的编号,程序员可以利用MPI提供的接口来给不同编号的进程分配不同的任务和帮助进程相互交流最终完成同一个任务。就好比包工头给工人们编上了工号然后指定一个方案来给不同编号的工人分配任务并让工人相互沟通完成任务。
Python中的并行
由于CPython中的GIL的存在我们可以暂时不奢望能在CPython中使用多线程利用多核资源进行并行计算了,因此我们在Python中可以利用多进程的方式充分利用多核资源。
Python中我们可以使用很多方式进行多进程编程,例如os.fork()来创建进程或者通过multiprocessing模块来更方便的创建进程和进程池等。在上一篇《Python多进程并行编程实践-multiprocessing模块》中我们使用进程池来方便的管理Python进程并且通过multiprocessing模块中的Manager管理分布式进程实现了计算的多机分布式计算。
与多线程的共享式内存不同,由于各个进程都是相互独立的,因此进程间通信再多进程中扮演这非常重要的角色,Python中我们可以使用multiprocessing模块中的pipe、queue、Array、Value等等工具来实现进程间通讯和数据共享,但是在编写起来仍然具有很大的不灵活性。而这一方面正是MPI所擅长的领域,因此如果能够在Python中调用MPI的接口那真是太完美了不是么。
MPI与mpi4py
mpi4py是一个构建在MPI之上的Python库,主要使用Cython编写。mpi4py使得Python的数据结构可以方便的在多进程中传递。
mpi4py是一个很强大的库,它实现了很多MPI标准中的接口,包括点对点通信,组内集合通信、非阻塞通信、重复非阻塞通信、组间通信等,基本上我能想到用到的MPI接口mpi4py中都有相应的实现。不仅是Python对象,mpi4py对numpy也有很好的支持并且传递效率很高。同时它还提供了SWIG和F2PY的接口能够让我们将自己的Fortran或者C/C++程序在封装成Python后仍然能够使用mpi4py的对象和接口来进行并行处理。可见mpi4py的作者的功力的确是非常了得。
这里我开始对在Python环境中使用mpi4py的接口进行并行编程进行介绍。
MPI环境管理
mpi4py提供了相应的接口Init()和Finalize()来初始化和结束mpi环境。但是mpi4py通过在__init__.py中写入了初始化的操作,因此在我们from
mpi4py import MPI的时候就已经自动初始化mpi环境。
MPI_Finalize()被注册到了Python的C接口Py_AtExit(),这样在Python进程结束时候就会自动调用MPI_Finalize(),
因此不再需要我们显式的去掉用Finalize()。
通信域(Communicator)
mpi4py直接提供了相应的通信域的Python类,其中Comm是通信域的基类,Intracomm和Intercomm是其派生类,这根MPI的C++实现中是相同的。
同时它也提供了两个预定义的通信域对象:
包含所有进程的COMM_WORLD
只包含调用进程本身的COMM_SELF&
In&[1]:&from&mpi4py&import&MPI&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&In&[2]:&M_SELF&&&&&&&&&&&&&&&&&&&&&&&&&&&&Out[2]:&&mpi4py.MPI.Intracomm&at&0x7f2fa2fd59d0&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&In&[3]:&M_WORLD&&&&&&&&&&&&&&&&&&&&&&&&&&&&Out[3]:&&mpi4py.MPI.Intracomm&at&0x7f2fa2fd59f0&&&
通信域对象则提供了与通信域相关的接口,例如获取当前进程号、获取通信域内的进程数、获取进程组、对进程组进行集合运算、分割合并等等。
In&[4]:&comm&=&M_WORLD&&In&[5]:&comm.Get_rank()&&Out[5]:&0&&In&[6]:&comm.Get_size()&&Out[6]:&1&&In&[7]:&comm.Get_group()&&Out[7]:&&mpi4py.MPI.Group&at&0x7f2fa40fec30&&&In&[9]:&comm.Split(0,&0)&&Out[9]:&&mpi4py.MPI.Intracomm&at&0x7f2fa2fd5bd0&&&
关于通信域与进程组的操作这里就不细讲了,可以参考Introduction to Groups and Communicators
点对点通信
mpi4py提供了点对点通信的接口使得多个进程间能够互相传递Python的内置对象(基于pickle序列化),同时也提供了直接的数组传递(numpy数组,接近C语言的效率)。
如果我们需要传递通用的Python对象,则需要使用通信域对象的方法中小写的接口,例如send(),recv(),isend()等。
如果需要直接传递数据对象,则需要调用大写的接口,例如Send(),Recv(),Isend()等,这与C++接口中的拼写是一样的。
MPI中的点到点通信有很多中,其中包括标准通信,缓存通信,同步通信和就绪通信,同时上面这些通信又有非阻塞的异步版本等等。这些在mpi4py中都有相应的Python版本的接口来让我们更灵活的处理进程间通信。这里我只用标准通信的阻塞和非阻塞版本来做个举例:
阻塞标准通信
这里我尝试使用mpi4py的接口在两个进程中传递Python list对象。
from&mpi4py&import&MPI&&import&numpy&as&np&&comm&=&M_WORLD&&rank&=&comm.Get_rank()&&size&=&comm.Get_size()&&if&rank&==&0:&&&&&&data&=&range(10)&&&&&&comm.send(data,&dest=1,&tag=11)&&&&&&print(&process&{}&send&{}...&.format(rank,&data))&&else:&&&&&&data&=&comm.recv(source=0,&tag=11)&&&&&&print(&process&{}&recv&{}...&.format(rank,&data))&&
执行效果:
zjshao@vaio:~/temp_codes/mpipy$&mpiexec&-np&2&python&temp.py&&process&0&send&[0,&1,&2,&3,&4,&5,&6,&7,&8,&9]...&&process&1&recv&[0,&1,&2,&3,&4,&5,&6,&7,&8,&9]...&&
非阻塞标准通信
所有的阻塞通信mpi都提供了一个非阻塞的版本,类似与我们编写异步程序不阻塞在耗时的IO上是一样的,MPI的非阻塞通信也不会阻塞消息的传递过程中,这样能够充分利用处理器资源提升整个程序的效率。
来张图看看阻塞通信与非阻塞通信的对比:
非阻塞通信的消息发送和接受:
同样的,我们也可以写一个上面例子的非阻塞版本。
from&mpi4py&import&MPI&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&import&numpy&as&np&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&comm&=&M_WORLD&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&rank&=&comm.Get_rank()&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&size&=&comm.Get_size()&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&if&rank&==&0:&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&data&=&range(10)&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&comm.isend(data,&dest=1,&tag=11)&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&print(&process&{}&immediate&send&{}...&.format(rank,&data))&&else:&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&data&=&comm.recv(source=0,&tag=11)&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&print(&process&{}&recv&{}...&.format(rank,&data))&&
执行结果,注意非阻塞发送也可以用阻塞接收来接收消息:
zjshao@vaio:~/temp_codes/mpipy$&mpiexec&-np&2&python&temp.py&&process&0&immediate&send&[0,&1,&2,&3,&4,&5,&6,&7,&8,&9]...&&process&1&recv&[0,&1,&2,&3,&4,&5,&6,&7,&8,&9]...&&
支持Numpy数组
mpi4py的一个很好的特点就是他对Numpy数组有很好的支持,我们可以通过其提供的接口来直接传递数据对象,这种方式具有很高的效率,基本上和C/Fortran直接调用MPI接口差不多(方式和效果)
例如我想传递长度为10的int数组,MPI的C++接口是:
void&Comm::Send(const&void&*&buf,&int&count,&const&Datatype&&&datatype,&int&dest,&int&tag)&const&
在mpi4py的接口中也及其类似, Comm.Send()中需要接收一个Python list作为参数,其中包含所传数据的地址,长度和类型。
来个阻塞标准通信的例子:
from&mpi4py&import&MPI&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&import&numpy&as&np&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&comm&=&M_WORLD&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&rank&=&comm.Get_rank()&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&size&=&comm.Get_size()&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&if&rank&==&0:&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&data&=&np.arange(10,&dtype='i')&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&comm.Send([data,&MPI.INT],&dest=1,&tag=11)&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&print(&process&{}&Send&buffer-like&array&{}...&.format(rank,&data))&&else:&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&data&=&np.empty(10,&dtype='i')&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&comm.Recv([data,&MPI.INT],&source=0,&tag=11)&&&&&&&&&&&&&&&&&&&&&&&&&&&&print(&process&{}&recv&buffer-like&array&{}...&.format(rank,&data))&&
执行效果:
zjshao@vaio:~/temp_codes/mpipy$&/usr/bin/mpiexec&-np&2&python&temp.py&&process&0&Send&buffer-like&array&[0&1&2&3&4&5&6&7&8&9]...&&process&1&recv&buffer-like&array&[0&1&2&3&4&5&6&7&8&9]...&&
MPI组通信和点到点通信的一个重要区别就是,在某个进程组内所有的进程同时参加通信,mpi4py提供了方便的接口让我们完成Python中的组内集合通信,方便编程同时提高程序的可读性和可移植性。
下面就几个常用的集合通信来小试牛刀吧。
广播操作是典型的一对多通信,将跟进程的数据复制到同组内其他所有进程中。
在Python中我想将一个列表广播到其他进程中:
from&mpi4py&import&MPI&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&comm&=&M_WORLD&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&rank&=&comm.Get_rank()&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&size&=&comm.Get_size()&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&if&rank&==&0:&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&data&=&range(10)&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&print(&process&{}&bcast&data&{}&to&other&processes&.format(rank,&data))&&else:&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&data&=&None&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&data&=&comm.bcast(data,&root=0)&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&print(&process&{}&recv&data&{}...&.format(rank,&data))&&
执行结果:
zjshao@vaio:~/temp_codes/mpipy$&/usr/bin/mpiexec&-np&5&python&temp.py&&process&0&bcast&data&[0,&1,&2,&3,&4,&5,&6,&7,&8,&9]&to&other&processes&&process&0&recv&data&[0,&1,&2,&3,&4,&5,&6,&7,&8,&9]...&&process&1&recv&data&[0,&1,&2,&3,&4,&5,&6,&7,&8,&9]...&&process&3&recv&data&[0,&1,&2,&3,&4,&5,&6,&7,&8,&9]...&&process&2&recv&data&[0,&1,&2,&3,&4,&5,&6,&7,&8,&9]...&&process&4&recv&data&[0,&1,&2,&3,&4,&5,&6,&7,&8,&9]...&&
与广播不同,发散可以向不同的进程发送不同的数据,而不是完全复制。
例如我想将0-9发送到不同的进程中:
from&mpi4py&import&MPI&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&import&numpy&as&np&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&comm&=&M_WORLD&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&rank&=&comm.Get_rank()&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&size&=&comm.Get_size()&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&recv_data&=&None&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&if&rank&==&0:&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&send_data&=&range(10)&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&print(&process&{}&scatter&data&{}&to&other&processes&.format(rank,&send_data))&&else:&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&send_data&=&None&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&recv_data&=&comm.scatter(send_data,&root=0)&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&print(&process&{}&recv&data&{}...&.format(rank,&recv_data))&&
发散结果:
zjshao@vaio:~/temp_codes/mpipy$&/usr/bin/mpiexec&-np&10&python&temp.py&&process&0&scatter&data&[0,&1,&2,&3,&4,&5,&6,&7,&8,&9]&to&other&processes&&process&0&recv&data&0...&&process&3&recv&data&3...&&process&5&recv&data&5...&&process&8&recv&data&8...&&process&2&recv&data&2...&&process&7&recv&data&7...&&process&4&recv&data&4...&&process&1&recv&data&1...&&process&9&recv&data&9...&&process&6&recv&data&6...&&
收集过程是发散过程的逆过程,每个进程将发送缓冲区的消息发送给根进程,根进程根据发送进程的进程号将各自的消息存放到自己的消息缓冲区中。
收集结果:
zjshao@vaio:~/temp_codes/mpipy$&/usr/bin/mpiexec&-np&5&python&temp.py&&process&2&send&data&2&to&root...&&process&3&send&data&3&to&root...&&process&0&send&data&0&to&root...&&process&4&send&data&4&to&root...&&process&1&send&data&1&to&root...&&process&0&gather&all&data&[0,&1,&2,&3,&4]...&&
其他的组内通信还有归约操作等等由于篇幅限制就不多讲了,有兴趣的可以去看看MPI的官方文档和相应的教材。
mpi4py并行编程实践
这里我就上篇《》中的二重循环绘制map的例子来使用mpi4py进行并行加速处理。
我打算同时启动10个进程来将每个0轴需要计算和绘制的数据发送到不同的进程进行并行计算。
因此我需要将pO2s数组发散到10个进程中:
之后我需要在每个进程中根据接受到的pO2s的数据再进行一次pCOs循环来进行计算。
最终将每个进程计算的结果(TOF)进行收集操作:
comm.gather(tofs_1d,&root=0)&
由于代码都是涉及的专业相关的东西我就不全列出来了,将mpi4py改过的并行版本放到10个进程中执行可见:
效率提升了10倍左右。
本文简单介绍了mpi4py的接口在python中进行多进程编程的方法,MPI的接口非常庞大,相应的mpi4py也非常庞大,mpi4py还有实现了相应的SWIG和F2PY的封装文件和类型映射,能够帮助我们将Python同真正的C/C++以及Fortran程序在消息传递上实现统一。有兴趣的同学可以进一步研究一下,欢迎交流。
MPI for Python 2.0.0 documentation
MPI Tutorial
A Python Introduction to Parallel Programming with MPI
《高性能计算并行编程技术-MPI并行程序设计》
《MPI并行程序设计实例教程》&
【编辑推荐】
【责任编辑: TEL:(010)】
大家都在看猜你喜欢
头条头条热点头条原创
24H热文一周话题本月最赞
讲师:91526人学习过
讲师:125345人学习过
讲师:91250人学习过
精选博文论坛热帖下载排行
本书以一个模拟局域网组建为思路,介绍了与局域网组建各主要方面相关的知识及组建、配置方法。本书所介绍的内容主要包括:局域网组建规划、...
订阅51CTO邮刊

参考资料

 

随机推荐