问题
How can I modify the following code (adapted from http://materials.jeremybejarano.com/MPIwithPython/pointToPoint.html) so that every comm.Send
instance is received by root = 0
and the output printed. At the moment, only the first send command is received.
#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]
回答1:
If you do not know how many messages you will send, then you have to introduce a message marking the end of messages. You can use this generically by using special tags. To avoid providing a mismatching buffer for the termination message, you can use probe
checking what kind of message is coming in
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
There are many variations of this. For example, if you know that a message is the last message you can merge the termination message.
回答2:
If each process knows the number of messages to be sent, the following steps can be designed to solve the problem:
1) Reduce the number of message to be sent to root process. Each process sends to the root the number of messages it will later send. This operation is called a reduction and it can be performed by the function comm.reduce(...)
2) Receive all the messages on process 0.
Here is a code based on yours that should do the trick. It can be ran by 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]
According to the documentation of numpy.random() the Mersenne Twister pseudo-random number generator is initially seeded by a number extracted from /dev/urandom
(or the Windows analogue) if available or seed from the clock otherwise. Hence, in the last case, all processes can receive the same seed and generate the same random numbers. To prevent this from happening, I added the following line:
np.random.seed(np.random.randint(np.iinfo(np.uint32).min,np.iinfo(np.uint32).max)+rank)
来源:https://stackoverflow.com/questions/36091527/receive-multiple-send-commands-using-mpi4py