2016-03-18 30 views
4

comm.Sendインスタンスがすべてroot = 0で受信され、出力が出力されるように、次のコード(http://materials.jeremybejarano.com/MPIwithPython/pointToPoint.htmlから適合)を変更するにはどうすればよいですか。現時点では、最初の送信コマンドだけが受信されます。mpi4pyを使用して複数の送信コマンドを受信

#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] 
+0

明確にする/確認するだけです。ランク自体でも、各ランクがどれくらいのメッセージを送信するかを手前で知る機会がないと仮定していますか? – Zulan

+0

理想的には、ランクが送信するメッセージの数を知らなくても、各ランクからメッセージを送信したいと考えています。これが不可能な場合、ランク内で送信されるメッセージの数を計算することは可能ですが、これは各ランクごとに異なります。 – 218

答えて

3

送信するメッセージの数がわからない場合は、メッセージの最後にメッセージを挿入する必要があります。特別なタグを使用することでこれを一般的に使用することができます。終了メッセージのための不一致バッファを提供しないようにするには、

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 

に来ているメッセージの種類をチェックprobeを使用することができ、この多くのバリエーションがあります。たとえば、メッセージが最後のメッセージであることが分かっている場合は、終了メッセージをマージできます。

+0

これは 'comm.probe(status = s)'という行の' comm.probe(status = s)AttributeError: 'mpi4py.MPI.Intracomm'オブジェクトに 'probe'という属性がありません。 。また、あなたが選んだタグ番号には意味がありますか、 'tag_end'を' tag_data'と区別するだけでいいですか?または特定のプロセスのために特定の番号が予約されていますか? – 218

+0

おそらく、 'probe'がmpi4pyのバージョン2.0.0で導入されました。大文字のProbeで代用するだけで差はないはずです。タグ値は完全に任意であり、区別する必要があります。私の例の実際の値は[42](https://en.wikipedia.org/wiki/42_%28number%29#Hitchhiker.27s_Guide_to_the_Galaxy)と[23](https://en.wikipedia.org/)への参照です。 wiki/23_%28film%29)、私は実際には後者を見ていない。 – Zulan

+0

'comm.probe'はmpi4pyバージョン2.0.0にしか入っていないようです。私はこれを使って 'python3'をインストールし、あなたが投稿した元のコード(明らかに修正された' print'文)を持っています。しかし、古いバージョンのmpi4pyでは、 'comm.Probe'はプロセスをハングアップさせます。 'print"プロセスの行でも、ランクは "done"です。これは常に 'rank = 0'を出力します。おそらく 'rank'を' s.source'に置き換えると、 'tag_end'を送信したばかりの' rank'が出力されますか? – 218

1

各プロセスが送信するメッセージの数を知っている場合は、以下の手順で問題が解決するように設計することができる。

1)ルートプロセスに送信されるメッセージの数を減らします。各プロセスは、後に送信するメッセージの数をルートに送信します。この操作は、削減と呼ばれ、それはトリックを行う必要があり、あなたに基づいてコードがある。ここ

プロセス0上のすべてのメッセージを受信機能comm.reduce(...)

2)により行うことができます。これは、そうでない場合、クロックから入手可能であるか、またはシードdocumentation of numpy.random()メルセンヌツイスター擬似乱数生成器が最初/dev/urandomから抽出された数(またはWindowsアナログ)によって播種される場合による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] 

によって実行することができます。したがって、最後のケースでは、すべてのプロセスが同じシードを受け取り、同じ乱数を生成することができます。これを防ぐため、次の行を追加しました:

np.random.seed(np.random.randint(np.iinfo(np.uint32).min,np.iinfo(np.uint32).max)+rank) 
関連する問題