2

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

4

1 に答える 1

2

MPI には、ランク 1 からランク 0 までの 2 つのメッセージが、送信された順序でランク 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 のメッセージ A が取得されますが、タグ 2 を使用するとランク 2 のメッセージ D が取得されます (上記のメッセージ キューは上記の順序保証を満たしますが、ここでは役に立たないことに注意してください)。 )。

これにはいくつかの方法があります。newdeltaw1 つは、受信したメッセージをタグだけでなくソース別にフィルタリングして、次のメッセージを送信したのと同じタスクからのものであることを確認すること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 メッセージのみが受信され、不一致が回避されます。

もう 1 つの方法は、両方のデータを同じメッセージに入れることで、メッセージの分割をまったく回避することです。

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)

これにより、両方のデータが 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
于 2014-05-15T11:25:13.307 に答える