Python 确保两条消息来自同一MPI任务
我正在使用python(mpi4py)编写一个MPI编程。许多进程计算部分结果,并将索引和更新发送到主任务。我收集所有数据的代码如下所示Python 确保两条消息来自同一MPI任务,python,parallel-processing,mpi,mpi4py,Python,Parallel Processing,Mpi,Mpi4py,我正在使用python(mpi4py)编写一个MPI编程。许多进程计算部分结果,并将索引和更新发送到主任务。我收集所有数据的代码如下所示 if rank == 0: cb = dict((v,0) for v in graph) #print "initial is",cb while True: neww = comm.recv(source=ANY_SOURCE, tag=1) newdeltaw = comm.recv(sourc
if rank == 0:
cb = dict((v,0) for v in graph)
#print "initial is",cb
while True:
neww = comm.recv(source=ANY_SOURCE, tag=1)
newdeltaw = comm.recv(source=ANY_SOURCE, tag=2)
print "newdelw is",newdeltaw,"neww is",neww
cb[neww]=cb[neww]+newdeltaw
print "cb=",cb
但是这里有一个竞争条件,它会影响我对大量处理器的结果-我可能会遇到这样的情况,
cb[neww]=cb[neww]+newdeltaw
,其中news
和newdeltaw
的数据来自不同的进程。如何防止这种情况发生?虽然MPI有顺序保证,即从秩1到秩0的两条消息将由秩0按其发送的顺序接收-一条消息不能超过另一条消息-MPI对它们将如何与来自其他处理器的其他消息交织在一起一事不置可否。因此,您可以轻松获得以下情况:
rank 1 messages to rank 0: [src 1, msg A, tag 1], [src 1, msg B, tag 2]
rank 2 messages to rank 0: [src 2, msg C, tag 1], [src 2, msg D, tag 2]
rank 0 message queue: [src 1, msg A, tag 1], [src 2, msg C, tag 1], [src 2, msg D, tag 2], [src 1, msg B, tag 2]
因此,秩0提取带有标记1的消息将得到秩1的msg a,而带有标记2的消息将得到秩2的msg D。(注意,上面的消息队列满足上面的顺序保证,但在这里对我们没有帮助)
有几种方法可以解决这个问题。一种是不仅按标签而且按来源过滤为newdeltaw
接收的消息,以确保它来自发送neww
的同一任务:
if rank == 0:
cb = numpy.zeros(size)
rstat = MPI.Status()
for i in range((size-1)*3):
neww = comm.recv(source=MPI.ANY_SOURCE, tag=1, status=rstat)
src = rstat.Get_source()
newdeltaw = comm.recv(source=src, tag=2)
print "newdelw is",newdeltaw,"neww is",neww
cb[neww]=cb[neww]+newdeltaw
print "cb=",cb
else:
data = rank
for i in range(3):
comm.send(rank,dest=0,tag=1)
comm.send(data,dest=0,tag=2)
这样,只接收来自匹配源的tag-2newdeltaw消息,避免了不一致性
另一种方法是通过将两段数据放在同一条消息中来避免拆分消息:
if rank == 0:
cb = numpy.zeros(size)
rstat = MPI.Status()
for i in range((size-1)*3):
(neww,newdeltaw) = comm.recv(source=MPI.ANY_SOURCE, tag=1)
print "newdelw is",newdeltaw,"neww is",neww
cb[neww]=cb[neww]+newdeltaw
print "cb=",cb
else:
data = rank
for i in range(3):
comm.send((rank,data),dest=0,tag=1)
这会将两段数据捆绑到一条消息中,因此它们不能分离。(请注意,一旦这起作用,您可以使用更高效的低级mpi4py例程来避免对元组进行序列化:
if rank == 0:
cb = numpy.zeros(size)
rstat = MPI.Status()
for i in range((size-1)*3):
dataarr = numpy.zeros(2,dtype='i')
comm.Recv([dataarr,MPI.INT],source=MPI.ANY_SOURCE, tag=1)
newdeltaw = dataarr[0]
neww = dataarr[1]
print "newdelw is",newdeltaw,"neww is",neww
cb[neww]=cb[neww]+newdeltaw
print "cb=",cb
else:
data = rank
for i in range(3):
senddata = numpy.array([rank,data],dtype='i')
comm.Send([senddata, MPI.INT],dest=0,tag=1)
最后,您可以完全避免主/从方法,让所有处理器处理问题中的部分结果,然后在最后使用reduce操作组合所有结果:
cb = numpy.zeros(size,dtype='i')
totals = numpy.zeros(size,dtype='i')
data = rank
for i in range(3):
cb[rank] = cb[rank] + data
comm.Reduce([cb,MPI.INT], [totals,MPI.INT], op=MPI.SUM, root=0)
if rank == 0:
print "result is", totals
现在还不清楚你在问什么。对于大的输入,你的程序是如何工作得不好的?是什么让你认为你需要锁定某个东西?我是否有这样一种情况,
cb[neww]=cb[neww]+newdeltaw
其中neww
和newdeltaw
的数据来自不同的进程。send
的代码驻留在主程序中,而不是驻留在一个中,如果有条件
像给定的代码一样,我仍然不明白为什么需要锁。秩0将从某个处理器接收一个neww,然后从另一个处理器接收一个newdeltaw一些(可能是其他)处理器,并更新cb[neww]因此,这里没有任何东西需要锁定。你想完成什么,什么不起作用?请提供一段简单的代码,重现你遇到的问题。当从一个进程接收到“neww”而从另一个进程接收到newdelta
时会发生什么?是否会发生类似的情况?是的,它可能发生如果你不想发生这种情况,将a传递给comm.recv,使用Get_source
查找你刚收到的源代码,并从该源代码而不是ANY_source
接收newdeltaw。或者,将neww和newdeltaw打包到一条消息中。这两种方法都不涉及锁定。