确保两条消息来自同一MPI任务

时间:2014-05-14 09:55:25

标签: 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(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来自newsnewdeltaw的数据来自不同的情况处理。我该如何防止这种情况?

1 个答案:

答案 0 :(得分:2)

虽然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] 

因此,提取具有标记1的消息的等级0将获得等级1的消息,但是随后标记2将获得等级2的消息(注意,上面的消息队列满足于以上订单保证,但在这里没有帮助我们。)

有几种解决方法。一种方法是过滤收到的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-2 newdeltaw消息,避免了不一致。

另一种方法是通过将两个数据放入同一个消息中来避免拆分消息:

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)

最后,您可以完全避免主/从方法,让所有处理器处理问题的部分结果,然后将所有结果与减少操作结合起来:

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