使用mpi4py接收多个发送命令

时间:2016-03-18 18:13:33

标签: python numpy mpi mpi4py

如何修改以下代码(改编自http://materials.jeremybejarano.com/MPIwithPython/pointToPoint.html),以便comm.Send收到每个root = 0实例并打印输出。目前,只收到第一个发送命令。

#passRandomDraw.py
import numpy
from mpi4py import MPI
from mpi4py.MPI import ANY_SOURCE
import numpy as np

comm = MPI.COMM_WORLD
rank = comm.Get_rank()

if rank == 0:
    randNum = numpy.zeros(1)
    print "Process before receiving random numbers"


else:
    for i in range(0,np.random.randint(1,10),1):
        randNum = numpy.zeros(1)
        randNum = numpy.random.random_sample(1)
        print "Process", rank, "iteration", i, "drew the number", randNum[0]
        comm.Send(randNum, dest=0)


if rank == 0:
   comm.Recv(randNum, ANY_SOURCE)
   print "Process", rank, "received the number", randNum[0]

2 个答案:

答案 0 :(得分:3)

如果您不知道要发送的邮件数量,那么您必须引入一条标记邮件结尾的邮件。您可以通过使用特殊标记来使用它。为避免为终止消息提供不匹配的缓冲区,您可以使用probe检查传入的消息类型

tag_data = 42
tag_end = 23

if rank == 0:
    randNum = numpy.zeros(1)
    print "Process before receiving random numbers"
else:
    for i in range(0,np.random.randint(1,10),1):
        randNum = numpy.zeros(1)
        randNum = numpy.random.random_sample(1)
        print "Process", rank, "iteration", i, "drew the number", randNum[0]
        comm.Send(randNum, dest=0, tag=tag_data)
    # send the termination message. Using the lower-case interface is simpler
    comm.send(None, dest=0, tag=tag_end)

if rank == 0:
    # For debugging it might be better to use a list of still active procsses
    remaining = comm.Get_size() - 1
    while remaining > 0:
        s = MPI.Status()
        comm.Probe(status=s)
        # make sure we post the right kind of message
        if s.tag == tag_data:
            comm.Recv(randNum, s.source, tag=tag_data)
            print "Process ", s.source, " received the number", randNum[0]
        elif s.tag == tag_end:
            # don't need the result here
            print "Process ", rank, " is done"
            comm.recv(source=s.source, tag=tag_end)
            remaining -= 1

这有很多变化。例如,如果您知道消息是最后一条消息,则可以合并终止消息。

答案 1 :(得分:1)

如果每个进程都知道要发送的消息数,可以设计以下步骤来解决问题:

1)减少要发送到根进程的消息数量。每个进程向根发送它稍后将发送的消息数。此操作称为缩减,可以通过函数comm.reduce(...)

执行

2)接收进程0上的所有消息。

这是一个基于你的代码应该可以解决的问题。它可以由mpirun -np 4 python main.py

运行
#passRandomDraw.py
import numpy
from mpi4py import MPI
from mpi4py.MPI import ANY_SOURCE
import numpy as np

comm = MPI.COMM_WORLD
rank = comm.Get_rank()
size = comm.Get_size()

#just in case, if numpy.random is seed with 
np.random.seed(np.random.randint(np.iinfo(np.uint32).min,np.iinfo(np.uint32).max)+rank)

if rank == 0:
    randNum = numpy.zeros(1)
    print "Process before receiving random numbers"
    nb=np.empty((1,),dtype=int)
    nb0=np.zeros((1,),dtype=int)
    comm.Reduce([nb0, MPI.INT],[nb, MPI.INT],op=MPI.SUM, root=0)  #sums the total number of random number from every process on rank 0, in nb.
    #print "rank"+str(rank)+" nb "+str(nb)
else:
    nb=np.empty((1,),dtype=int)
    nb[0]=np.random.randint(1,10)
    #print "rank"+str(rank)+" nb "+str(nb)
    comm.Reduce([nb, MPI.INT],None,op=MPI.SUM, root=0)
    for i in range(0,nb[0],1):
        randNum = numpy.zeros(1)
        randNum = numpy.random.random_sample(1)
        print "Process", rank, "iteration", i, "drew the number", randNum[0]
        comm.Send(randNum, dest=0)



if rank == 0:
   for i in range(nb[0]): #receives nb message, each one with its int.
       comm.Recv(randNum, ANY_SOURCE)
       print "Process", rank, "received the number", randNum[0]

根据documentation of numpy.random() Mersenne Twister伪随机数生成器最初由从/dev/urandom(或Windows模拟)中提取的数字(如果可用)或来自时钟的种子播种。因此,在最后一种情况下,所有进程都可以接收相同的种子并生成相同的随机数。为了防止这种情况发生,我添加了以下行:

np.random.seed(np.random.randint(np.iinfo(np.uint32).min,np.iinfo(np.uint32).max)+rank)