mpi 4 pyのクライアント-サーバプログラミング

5859 ワード

前回ではmpi 4 pyのOpオブジェクトを紹介しましたが、mpi 4 pyのクライアントサーバプログラミングを紹介します。
MPIは、同じ通信サブオブジェクトを持たない2つのプロセスグループ間で通信連絡を確立することを可能にする。この機能は、多くの場合に適用されます。
  • アプリケーションは2つの部分に分けられ、それぞれ独立して起動しますが、実行時には通信連絡を確立する必要があります。
  • のいくつかの可視化ツールは、実行中のプロセスに接続する必要があります。
  • 並列のserverプログラムは、複数の並列のclientと接続を確立する必要があるかもしれない。
  • MPIは、複数の通信接続APIを提供し、これらの通信連絡APIは、2つのグループのプロセスの間でグループ間通信子を確立することによって、上述の要求の機能を実現する。
    通信子を共有しない2つのプロセスグループの間で連絡を確立する動作は、非対称的なセット操作であり、プロセスのセットを強制的に傍受状態にして、別のプロセスの接続要求のセットを受信する必要がある。MPIによると、要求を待ち受けるプロセスのセットはパラレルサービスプロセスであり、サービスグループに接続しようとするプロセスはクライアントと呼ばれる。
    あらかじめ存在している接続チャネルがないので、クライアントとサーバの間では、いくつかのキーの同期点について合意する必要がある。これはもう一つの第三のメカニズムが必要です。MPIはこのために名前サービスインターフェース(外部ドメイン名サービスと対応可能)を設置し、リリース可能なポート番号を通じてserver端とclient端に接続を確立する。ポート番号は、TCP/IPポートであっても良いし、システムが他の任意のプロトコルを使用して定義される底層通信ポートであってもよい。MPIは名前のリリースメカニズムによって、ポート番号とサービスを結びつけて、フォーマットでリリースすることもできます。ポート番号、サービス及びそのリリースメカニズムも柔軟性と移植性の間の折衷である。ポート番号だけで最高の移植性が保証されますが、手を加えてclientに知らせる必要があるので、使いにくいです。名前のリリースメカニズムを使用してポート番号、サービスバインディングを行うことで、名前のリリースをサポートするバージョンの中で最高の移植性が得られます。アプリケーション内でポート発見メカニズムをカスタマイズすることもできます。この方法は最も柔軟ですが、移植性は最悪です。
    サーバ端
    サーバー側はまずMPI.Open_を呼び出します。ポートを開けて、MPI.Intram.Acceptを呼び出して、クライアントの接続を待つ。
    MPI.Open_port(Info info=INFO_NULL)
    
    ポートを開き、開いているポートの名前を返します。ポート名は、infoパラメータに関連してMPI環境に伝達することもでき、文字列サイズはMPI.MAX_によってもよい。PORT_NAME指定。送信者のinfoオブジェクトがポートのオープンに関する指示をしない場合、MPI.INFO(u)の値を設定することができます。NULLは、デフォルトのオープンポート機構を使用することを表しています。注意:開いているポート番号はMPI.C lose_を通ります。ポートは、MPI環境を介してリリースされる前に重複して使用することができません。また、MPI-2はTCP/IP方式の通信接続のためにキーワードip_を予約しています。ポロとipaddressは、この関数だけで使用されます。
    MPI.Close_port(port_name)
    
    開いているポートport_nameを閉じ、占有されているリソースを解放する。
    MPI.Intracomm.Accept(self, port_name, Info info=INFO_NULL, int root=0)
    
    クライアントとの通信接続を確立し、現在の通信子上でセット操作を行い、クライアントとの通信が可能なグループ間通信サブオブジェクトを返す。port_nameは、制御接続のための補助情報を伝達するための有効なポートであり、infoは、現在の通信サブのルートプロセスである。一つのサーバが複数のクライアントとの接続を同時に受ける必要がある場合は、MPI.Introm.Acceptを個々のスレッドで呼び出す必要がある。サーバ端は、クライアント接続がない場合を処理するために別途スレッドを使用しても良い。
    クライアント
    MPI.Intracomm.Connect(self, port_name, Info info=INFO_NULL, int root=0)
    
    ポートrootを介してサーバ端に接続され、現在の通信サブオブジェクト上でセット操作され、MPI.Introm.Acceptを実行するサーバ端プロセスからなるグループ間通信サブオブジェクトに戻る。port_nameは、制御接続のための補助情報を伝達するために使用され、infoは、現在の通信子におけるルートプロセスである。
    MPI.Comm.Disconnect(self)
    
    すべての通信動作が完了したら、通信子オブジェクトを解放し、MPI.NULLです。この方法はMPI.OMM_に対してはいけません。WORLDとMPI.OMM_SELF呼び出しは、通信中に必要なすべての通信動作が完了した時にのみ使用できます。通信が完了するのを待つ以外に、MPI.COMM.Freeの効果と似ています。2つのプロセス接続を切断すると、通常は、MPI.Win.FreeとMPI.File.Closeを呼び出して、2つのプロセスグループ間のすべての通信経路を削除します。
    名前の発表
    MPI.Publish_name(service_name, port_name, info=INFO_NULL)
    
    名前バインディングをサーバ側で公開します。一つのrootは、複数のport_nameをバインドしてもよく、その逆は必ずしも許可されていない。このようにサポートされる場合、名前検索時の決定情報はservice_nameオブジェクトを介して伝達される必要がある。
    MPI.Unpublish_name(service_name, port_name, info=INFO_NULL)
    
    名前のバインディングをサーバ側でキャンセルします。ポートを閉じる前に、名前サービスのバインディング関係をキャンセルしなければなりません。
    MPI.Lookup_name(service_name, info=INFO_NULL)
    
    infoに基づいて、バインディングされたservice_nameを取得する。
    MPI通信を確立する他の方法
    MPI.Comm.Join(type cls, int fd)
    
    二つのグループのMPIプロセスの間でソケットを介して通信接続を確立し、一つのグループ間の通信サブオブジェクトを返す。port_nameはSOCK_です。STREAMタイプのソケットファイル記述子です。ソケットは接続状態でなければなりません。MPI.Commm.Joinを呼び出した時はアクティブではありません。ソケットの両端のプロセスはこの方法を呼び出す必要があります。両端のプロセスは呼び出しから戻ります。グループ間通信のサブオブジェクトを取得することができます。
    ルーチン
    以下に使用例を示します。
    サーバ側プログラム
    # server.py
    
    """
    Server side of the MPI client/server programming model.
    
    Run this with 1 processes like:
    $ mpiexec -n 1 python server.py
    """
    
    import numpy as np
    from mpi4py import MPI
    
    
    comm = MPI.COMM_WORLD
    
    service_name = 'compute'
    # open a port
    port_name = MPI.Open_port()
    # bind the opened port to a service_name,
    # client can connect to the port by looking-up this service_name
    MPI.Publish_name(service_name, port_name)
    # wait for client to connect
    inter_comm = comm.Accept(port_name)
    
    # receive message from client
    recv_obj = inter_comm.recv(source=0, tag=0)
    print 'Server receives %s from client.' % recv_obj
    send_obj = eval(recv_obj)
    # reply the result to the client
    print 'Server sends %s to client.' % send_obj
    inter_comm.send(send_obj, dest=0, tag=1)
    
    # unpublish the service_name, close the port and disconnect
    MPI.Unpublish_name(service_name, port_name)
    MPI.Close_port(port_name)
    inter_comm.Disconnect()
    
    クライアントプログラム
    # client.py
    
    """
    Client side of the MPI client/server programming model.
    
    Run this with 1 processes like:
    $ mpiexec -n 1 python client.py
    """
    
    import numpy as np
    from mpi4py import MPI
    
    
    comm = MPI.COMM_WORLD
    
    service_name = 'compute'
    # get the opened port of the server by looking-up a service_name
    port_name = MPI.Lookup_name(service_name)
    # connect to the server
    inter_comm = comm.Connect(port_name)
    
    # send message to the server
    send_obj = '1 + 2'
    print 'Client sends %s to server.' % send_obj
    inter_comm.send(send_obj, dest=0, tag=0)
    # get results from the server
    recv_obj = inter_comm.recv(source=0, tag=1)
    print 'Client receives %s from server.' % recv_obj
    
    # disconnect from the server
    inter_comm.Disconnect()
    
    まずサーバ端末プログラムを起動し、他の端末でクライアントプログラムを起動する必要があります。
    運転結果は以下の通りです。
    サーバ側の結果:
    $ mpiexec -report-pid - -n 1 python server.py
    31310
    Server receives 1 + 2 from client.
    Server sends 3 to client.
    
    クライアントの結果:
    $ mpiexec -ompi-server pid:31310 -n 1 python client.py
    Client sends 1 + 2 to server.
    Client receives 3 from server.
    
    注意:上記の運転はOpenMPIのみに適用されますので、他のMPIについては、その関連文書を参照してください。
    以上はmpi 4 pyのクライアントサーバプログラミング方法を紹介しました。次のページではmpi 4 pyの中のmemoryオブジェクトとメモリ操作を紹介します。