MPI消息传递接口(2)——信息传输
来源:互联网 发布:离坚白 知乎 编辑:程序博客网 时间:2024/06/05 03:05
MPI(Message-Passing-Interface)消息传递接口
1.点对点传输
点对点通信.其实就是最简单的进程A向进程B发送信息,而进程B向进程A接收信息.这是关于两个进程之间的通信.
示例代码:
#mpip2p.pyfrom mpi4py import MPIcomm = MPI.COMM_WORLDcomm_rank = comm.Get_rank()comm_size = comm.Get_size()data = [comm_rank]*5comm.send(data,dest=(comm_rank+1)%comm_size)data_recv =comm.recv(source=(comm_rank-1)%comm_size)print "my rank is %d, and Ireceived:" %comm_rankprint data_recv
在命令行中输入命令
mpiexec -n 5 python mpip2p.py
执行结果:
my rank is 4, and Ireceived:[3, 3, 3, 3, 3]my rank is 3, and Ireceived:[2, 2, 2, 2, 2]my rank is 2, and Ireceived:[1, 1, 1, 1, 1]my rank is 0, and Ireceived:[4, 4, 4, 4, 4]my rank is 1, and Ireceived:[0, 0, 0, 0, 0]
指定启动5个mpi进程来执行后面的程序。相当于对脚本拷贝了5份,每个进程运行一份,互不干扰。在运行的时候代码里面唯一的不同,就是各自的rank也就是ID不一样。
Get_rank()函数:获取当前进程rank值
Get_size()函数:获取总共的进程数
send()函数:将数据送给rank为dest的值的进程
recv()函数:接收rank为source的值的数据
消息传递的同步异步性:
recv是阻塞函数,也就是说进程要收到发送方的数据,这个函数才返回.
而send是不确定的,也就是说它有时候是阻塞,有时候是非阻塞.当发送的数据不多的时候,mpi会将数据存到一个系统缓冲区,然后马上进行send方法的返回.而当数据量很大超过缓冲区的大小的时候,mpi需要等待接收方接收,然后把数据拷贝给接收方,再进行send方法的返回.
简单来说,数据量少->非阻塞(同步),数据量大->阻塞(异步).
除了send和recv方法,还有Send和Recv方法.,这样区分是由于要传递的数据的性质差异.当我们要传递int,float,list,dict等python内置类型的数据的时候,我们使用小写的方法.而当使用buffer类型的数据的时候,我们要使用大写的方法.
send的多个版本:
事实上,除了大写小写的版本,send还有不同的版本,这个不同是基于不同的发送策略的,而这些版本都有大小写之分.
bsend:缓冲模式,数据写入缓冲区,马上返回,用户必须确保缓冲区大小足够
ssend:同步模式,等接收方接收才返回
rsend:就绪模式,发送时必须确保接收方处于等待接收的状态,否则产生错误
send:标准模式(bsend+ssend),send实际上就是bsend和ssend的结合体.
2.多点传输:
#mpimp.pyfrom mpi4py import MPIcomm = MPI.COMM_WORLDcomm_rank = comm.rank()comm_size = comm.size()if comm_rank == 0: data = [1,2,3] for i in range(comm_size - 1): comm.send(data,dest=i+1)else: data = comm.recv(source = 0) print "Process %d receive"%comm_rank,data
运行结果:
mpiexec -n 6 python mpimp.py
Process 1 receive [1,2,3]Process 2 receive [1,2,3]Process 3 receive [1,2,3]Process 4 receive [1,2,3]Process 5 receive [1,2,3]
此做法漏洞:
在单机上跑这n个进程好像没所谓,CPU始终在工作,时间复杂度也是O(n)级别.
但假如是n台机器分别跑这n个进程,第0台机器始终在发送数据,而其他机器的大部分时间都在排队,等第0台机器往自己发送数据.这样的话,这堆机器要运行完这堆进程,需要O(n)时间.等于一台机器的工作效率,不是满意的结果。
广播(改进):
想到了,我们可以像p2p那样做,有数据的机器都帮忙向没有数据的机器发送数据,这样的话时间复杂度是可以降低到O(logn)的!
mpi有实现这样操作的接口,bcast函数
改进代码:
#mpimp.pyfrom mpi4py import MPIcomm = MPI.COMM_WORLDcomm_rank = comm.rank()comm_size = comm.size()if comm_rank == 0: data = [1,2,3] comm.bcast(data, root=0)else: data = comm.bcast(None, root=0) print "Process %d receive"%comm_rank,data
bcast()函数:无论是广播者,还是被广播者,都是调用bcast函数,而不像点对点那样一个send另一个recv.bcast()函数一个根进程把数据发给其他进程。
散播:
散播的函数和广播的参数是一样的,只是返回值不一样.
注意!散播的发送方也会接收到数据(和概念图有出入),
散播里列表里元素的分发不是按进程0就分得第0个元素,进程1就第1个元素这样的.而是一种类似随机的打乱的分发策略.
散播发送的数据,data(列表)里元素的个数必须等于进程的个数.否则会出错。
示例代码:
#mpisca.pyfrom mpi4py import MPIcomm = MPI.COMM_WORLDcomm_rank = comm.Get_rank()comm_size = comm.Get_size()if comm_rank == 0: data = [1,2,3,4,5,6]else: data = Nonedata = comm.scatter(data, root=0) print "Process %d receive"%comm_rank,data
运行结果:
mpiexec -n 6 python mpisca.pyProcess 1 receive 2Process 4 receive 5Process 2 receive 3Process 0 receive 1Process 3 receive 4Process 5 receive 6
收集:
散播的逆操作:
#mpigather.pyfrom mpi4py import MPIcomm = MPI.COMM_WORLDcomm_rank = comm.Get_rank()comm_size = comm.Get_size()if comm_rank == 0: data = comm.gather(comm_rank, root=0) print dataelse: comm.gather(comm_rank,root=0)
mpiexec -n 8 python mpigather.py[0, 1, 2, 3, 4, 5, 6, 7]
reduce()规约函数:
它相当于在收集的过程中不断地进行两元运算,最终在接收方那里只有一个值,而不是一个列表.
也就是说规约函数
示例代码:通过1−13+15−17+...=π4 计算圆周率
#mpireduce.pyfrom mpi4py import MPIcomm = MPI.COMM_WORLDcomm_rank = comm.Get_rank()comm_size = comm.Get_size()k = (1.0 if comm_rank%2 == 0 else -1.0)/(2*comm_rank +1)data = comm.reduce(k, root=0,op=MPI.SUM)if comm_rank == 0: pi = data*4 print "PI = %.6f"%pi
运行结果:
C:\Python27\Scripts\ML\MPI>mpiexec -n 12 python mpireduce.pyPI = 3.058403
注意事项:
1.并行计算的reduce,scatter,gather在执行信息交互函数是并行,信息交互完之后,每个进程统一从函数中出来,执行接下来的代码
2.上述函数root秩代表根节点:scatter传播,gather接收,reduce最终汇总结果的进程,
3每台机器reduce复杂度,只有O(logn),reduce函数MPI_SUMj操作:
假设九个进程
1, 2, 3, 4, 5, 6, 7, 8, 9 1+2, 3+4, 5+6, 7+8, 9 1+2+3+4, 5+6+7+8, 9 1+2+3+4+5+6+7+8, 9 1+2+3+4+5+6+7+8+9
4.单机的话不要开几百个进程,不是开玩笑的
5.注意的是,散播和reduce中发送接收到的返回值,不是接收方最终得到的返回值,而是一个none.
alltogether:收集后再广播一次,allreduce:reduce+bcast
barrier是一种全局同步,就是说全部进程进行同步.
当一个进程调用barrier的时候,它会被阻塞.
当所有进程都调用了barrier之后,barrier会同时解除所有进程的阻塞.
但运行起来发现并不是这回事.所有进程没有像期待那样先全部输出begin,再全部输出end,barrier这个函数仿佛形同虚设.
其实这里问题不是在barrier,而是在print.
我们OS的IO是有缓冲的,一个数据要出现在屏幕上,简单来说是经过内存->标准IO文件->控制台屏幕.
而进程间不共享IO文件(后面会学到如何在MPI的进程里共享文件),共享控制台屏幕.
因此屏幕上语句的顺序依赖OS什么时候将IO文件里的内容推到屏幕上.
我们强制让内存->标准IO文件和标准IO文件->控制台屏幕这两步一起进行,也就是加上flush语句.
form mpi4py import MPIimport syscomm = MPI.COMM_WORLDcomm_rank = comm.Get_rank()comm_size = comm.Get_size()print comm_rank,'begin'sys.stdout.flush()comm.barrier()print comm_rank,'end'
sendrecv()函数
发送send+接收recv
data = sendrecv(data,dest=1)
关于进程
from mpi4py import MPIcomm = MPI.COMM_WORLDcomm_rank = comm.Get_rank()comm_size = comm.Get_size()data_send = [comm_rank]*5comm.send(data_send,dest=(comm_rank+1)%comm_size)data_recv = comm.recv(source=(comm_rank-1)%comm_size)print (my rank is %d, and Ireceived: %comm_rank)print data_recv
这里面有个需要注意的问题,如果我们要发送的数据比较小的话,mpi会缓存我们的数据,然后继续执行后面的指令,而不会等待对方进程执行recv指令接收这个数据。
但是,如果要发送数据量很大,[rank]*500程序就会很卡,因为所有进程都会卡在发送这条指令,等待下一个指令发起接收指令,但是进程是执行完发送的指令才能接收的指令,这就和死锁差不多。
一般修改如下:
from mpi4py import MPIcomm = MPI.COMM_WORLDcomm_rank = comm.Get_rank()comm_size = comm.Get_size()data_send = [comm_rank]*500if comm_rank == 0: comm.send(data_send, dest=(comm_rank+1)%comm_size)if comm_rank > 0: data_recv = comm.recv(source=(comm_rank-1)%comm_size) comm_send(data_send,dest=(comm_rank-1)%comm_size)if comm_rank == 0: data_recv = comm.recv(source=(comm_rank-1)%comm_size)
这也就是为什么接收放在前面的原因了
阅读全文
0 0
- MPI消息传递接口(2)——信息传输
- MPI消息传递接口(1)——安装
- Windows应用程序信息传递—消息机制
- 五、无线信息传递——通过ssid传递对hostapd传输方式的具体说明
- 基于消息队列的信息传输机制
- iOS——消息传递
- MPI—HelloWorld
- MPI—并行求和
- MPI—点对点通信
- MPI—双机运行
- 【软考】——信息传输安全
- JAVA接口http协议传输—Hessian
- 如何通过消息传递字符串信息
- 04 MPI消息
- Android窗口管理(2)——消息传递
- ios的消息传递—— performSelector
- ios的消息传递—— performSelector
- 框架——消息传递机制
- 02 Activity窗口对象上的布局
- 如何在Ubuntu上安装Wine 2.6
- 读Spring源码的一些杂乱思绪(二)
- @Value读取配置文件,中文字符乱码
- const的普通用法及其在对象中的使用
- MPI消息传递接口(2)——信息传输
- 2017数学建模总结
- 滚动界面预加载的实现原理
- C#--实例选号器--实现删除和清空
- 士兵的数字游戏
- 关于如何写代码
- mysql和oracle的区别
- 过拟合样例代码以及几种算法的多项式过拟合比较
- windows10下的caffe框架的编译