2

私はOpenMPIを学んでいます。簡単な例を試しましたMPI_Scatter

#include <mpi.h>

using namespace std;

int main() {
    int numProcs, rank;

    MPI_Init(NULL, NULL);
    MPI_Comm_size(MPI_COMM_WORLD, &numProcs);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);

    int* data;
    int num;

    data = new int[5];
    data[0] = 0;
    data[1] = 1;
    data[2] = 2;
    data[3] = 3;
    data[4] = 4;
    MPI_Scatter(data, 5, MPI_INT, &num, 5, MPI_INT, 0, MPI_COMM_WORLD);
    cout << rank << " recieved " << num << endl; 

    MPI_Finalize();
    return 0;
}

しかし、期待通りにはいかなかった...

私は何かを期待していた

0 received 0
1 received 1 
2 received 2 ... 

しかし、私が得たのは

32609 received 
1761637486 received 
1 received 
33 received 
1601007716 received 

奇妙なランクとは何ですか?私のスキャッターと何か関係があるようですか?また、なぜsendcountrecvcountが同じなのですか? 最初は、5 つの要素を 5 つのプロセッサに分散させているので、それぞれが 1 になるのではないかと考えました。だから私は使用する必要があります:

MPI_Scatter(data, 5, MPI_INT, &num, 1, MPI_INT, 0, MPI_COMM_WORLD);

しかし、これはエラーになります:

[JM:2861] *** An error occurred in MPI_Scatter
[JM:2861] *** on communicator MPI_COMM_WORLD
[JM:2861] *** MPI_ERR_TRUNCATE: message truncated
[JM:2861] *** MPI_ERRORS_ARE_FATAL: your MPI job will now abort

しかし、ルートプロセスと子プロセスを区別する必要があるのはなぜですか? この場合、ソース/ルートもコピーを取得しますか? もう 1 つのことは、他のプロセスも分散して実行されるかどうかです。おそらくそうではありませんが、なぜですか?MPIプログラムで見た場合、典型的ではないので、すべてのプロセスがこのコードを実行すると思いましたか?

if (rank == xxx) {

アップデート

実行することに気付きました。送信バッファと受信バッファは同じ長さでなければなりません...そしてデータは次のように宣言する必要があります:

int data[5][5] = { {0}, {5}, {10}, {3}, {4} };

列の長さは 5 として宣言されていますが、1 つの値しか初期化していないことに注意してください。ここで実際に何が起こっているのですか?このコードは正しいですか? 各プロセスが 1 つの値のみを受け取るようにしたいとします。

4

1 に答える 1

5

sendcount送信バッファ内の要素の数ではなく、プロセスに送信する要素の数です。ルート プロセスの送信バッファから * [コミュニケータ内のプロセス数] 要素を取得し、それをコミュニケータ内のすべてのプロセスに分散させますMPI_Scattersendcount

したがって、コミュニケーターの各プロセスに 1 つの要素を送信するには (5 つのプロセスがあると仮定します)、sendcountandrecvcountを 1 に設定します。

MPI_Scatter(data, 1, MPI_INT, &num, 1, MPI_INT, 0, MPI_COMM_WORLD);

可能なデータ型のペアには制限があり、それらはポイント ツー ポイント操作の場合と同じです。のタイプ マップは のタイプ マップrecvtypeと互換性がある必要がありますsendtype。つまり、基本的な基本データ型のリストが同じである必要があります。また、受信バッファは、受信したメッセージを保持するのに十分な大きさである必要があります (これより大きくても小さくはなりません)。最も単純なケースでは、送信側と受信側のデータ型は同じです。したがって、 sendcount-recvcountペアとsendtype-recvtypeペアは通常同じ結果になります。それらが異なる可能性がある例は、いずれかの側でユーザー定義のデータ型を使用する場合です。

MPI_Datatype vec5int;

MPI_Type_contiguous(5, MPI_INT, &vec5int);
MPI_Type_commit(&vec5int);

MPI_Scatter(data, 5, MPI_INT, local_data, 1, vec5int, 0, MPI_COMM_WORLD);

これは、送信側が型の 5 要素のメッセージを構築するのMPI_INTに対し、各受信側はメッセージを 5 要素整数ベクトルの単一インスタンスとして解釈するため、機能します。

( で受け取る要素の最大数を指定するMPI_Recvと、実際に受け取る量が少なくなる可能性があることに注意してください。これは で取得できますMPI_Get_count。対照的に、 で受け取る要素の予想数を指定すると、次の場合recvcountMPI_Scatterエラーがスローされます。受信したメッセージの長さは、約束されたものとまったく同じではありません。)

numおそらく、印刷された奇妙なランクはスタックの破損が原因であることがわかっているintでしょintMPI_Scatter

しかし、ルートプロセスと子プロセスを区別する必要があるのはなぜですか? この場合、ソース/ルートもコピーを取得しますか? もう 1 つのことは、他のプロセスも分散して実行されるかどうかです。おそらくそうではありませんが、なぜですか?MPIプログラムで見た場合、典型的ではないので、すべてのプロセスがこのコードを実行すると思いましたか?

Scatter や Gather などの一部の操作では、集団通信 (グループ通信) であるため、コミュニケーター内のルートと他のプロセス (別のコンピューターに存在する可能性があるため、ルートの子プロセスではありません) を区別する必要がありますが、単一のソース/宛先を使用します。したがって、単一のソース/宛先 (奇数のアウト) はルートと呼ばれます。送受信を正しく設定するには、すべてのプロセスが送信元/送信先 (ルート プロセス) を認識している必要があります。

Scatter の場合、ルート プロセスは (それ自体から) データを受け取り、Gather の場合、そのデータも最終結果に含めます。「インプレース」操作が使用されない限り、ルート プロセスにも例外はありません。これは、すべての集団通信機能にも当てはまります。

MPI_Allgatherルート ランクを提供しない のような、ルートのないグローバル通信操作もあります。むしろ、すべてのランクが収集中のデータを受け取ります。

コミュニケーター内のすべてのプロセスが関数を実行します (コミュニケーター内の 1 つのプロセスを除外しようとすると、デッドロックが発生します)。同じコードをやみくもに実行している別のコンピューター上のプロセスを想像できます。ただし、それぞれが異なるコミュニケーター グループに属し、異なるランクを持っている可能性があるため、機能は異なる方法で実行されます。各プロセスは、それがコミュニケーターのメンバーであるかどうかを認識し、それぞれが自身のランクを認識し、ルート プロセス (存在する場合) のランクと比較できるため、通信を設定したり、それに応じて追加のアクションを実行したりできます。

于 2012-11-05T03:10:42.940 に答える