web-dev-qa-db-ja.com

MPI_ScatterおよびMPI_GatherはCからどのように使用されますか?

これまでのところ、私のアプリケーションは整数のリストを含むtxtファイルを読み込んでいます。これらの整数は、マスタープロセス、つまりランク0のプロセッサによって配列に格納する必要があります。これは正常に機能しています。

ここで、プログラムを実行すると、それがマスタープロセスであるかどうかを確認するifステートメントがあり、そうである場合は、MPI_Scatterコマンドを実行しています。

私が理解していることから、これは配列を数値で細分化し、それをスレーブプロセスに渡します。つまり、すべてのランク> 0です。ただし、MPI_Scatterの処理方法がわかりません。スレーブプロセスはどのようにサブスクライブを取得するために「サブスクライブ」しますか?マスター以外のプロセスにサブ配列で何かをするように指示するにはどうすればよいですか?

マスタープロセスが配列から要素を送信し、スレーブに合計を追加してマスターに返す方法を示す簡単な例を誰かに教えてもらえますか?

これまでの私のコード:

#include <stdio.h>
#include <mpi.h>

//A pointer to the file to read in.
FILE *fr;

int main(int argc, char *argv[]) {

int rank,size,n,number_read;
char line[80];
int numbers[30];
int buffer[30];

MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);

fr = fopen ("int_data.txt","rt"); //We open the file to be read.

if(rank ==0){
printf("my rank = %d\n",rank);

//Reads in the flat file of integers  and stores it in the array 'numbers' of type int.
n=0;
while(fgets(line,80,fr) != NULL) {
  sscanf(line, "%d", &number_read);
  numbers[n] = number_read;
  printf("I am processor no. %d --> At element %d we have number: %d\n",rank,n,numbers[n]);
  n++;
}

fclose(fr);

MPI_Scatter(&numbers,2,MPI_INT,&buffer,2,MPI_INT,rank,MPI_COMM_WORLD);

}
else {
MPI_Gather ( &buffer, 2, MPI_INT, &numbers, 2, MPI_INT, 0, MPI_COMM_WORLD); 
printf("%d",buffer[0]);
}
MPI_Finalize();
return 0;
}
27
DSF

これは、MPIでの操作がどのように機能するかについての一般的な誤解です。特に、集団操作では、ランク0からのみブロードキャスト(_MPI_Bcast_)の使用を試みます。他のプロセッサに何らかの形でデータを「プッシュ」する呼び出しを期待しています。しかし、それは実際にはMPIルーチンが機能する方法ではありません。ほとんどのMPI通信には送信者とMPI呼び出しを行うレシーバー。

特に、MPI_Scatter()およびMPI_Gather()(および_MPI_Bcast_など)はcollectiveです。オペレーション;コミュニケーター内のすべてのタスクallから呼び出す必要があります。コミュニケーター内のすべてのプロセッサが同じ呼び出しを行い、操作が実行されます。 (それが、スキャッターとギャザーの両方がパラメーターの1つとして「ルート」プロセスを必要とする理由です。このプロセスでは、すべてのデータが出入りします。)このようにすることで、MPI実装には、通信パターンを最適化するための多くのスコープがあります。

だから、ここに簡単な例を示します(更新済みギャザーを含める):

_#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {
    int size, rank;

    MPI_Init(&argc, &argv);
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);

    int *globaldata=NULL;
    int localdata;

    if (rank == 0) {
        globaldata = malloc(size * sizeof(int) );
        for (int i=0; i<size; i++)
            globaldata[i] = 2*i+1;

        printf("Processor %d has data: ", rank);
        for (int i=0; i<size; i++)
            printf("%d ", globaldata[i]);
        printf("\n");
    }

    MPI_Scatter(globaldata, 1, MPI_INT, &localdata, 1, MPI_INT, 0, MPI_COMM_WORLD);

    printf("Processor %d has data %d\n", rank, localdata);
    localdata *= 2;
    printf("Processor %d doubling the data, now has %d\n", rank, localdata);

    MPI_Gather(&localdata, 1, MPI_INT, globaldata, 1, MPI_INT, 0, MPI_COMM_WORLD);

    if (rank == 0) {
        printf("Processor %d has data: ", rank);
        for (int i=0; i<size; i++)
            printf("%d ", globaldata[i]);
        printf("\n");
    }

    if (rank == 0)
        free(globaldata);

    MPI_Finalize();
    return 0;
}
_

実行すると次のようになります。

_gpc-f103n084-$ mpicc -o scatter-gather scatter-gather.c -std=c99
gpc-f103n084-$ mpirun -np 4 ./scatter-gather
Processor 0 has data: 1 3 5 7 
Processor 0 has data 1
Processor 0 doubling the data, now has 2
Processor 3 has data 7
Processor 3 doubling the data, now has 14
Processor 2 has data 5
Processor 2 doubling the data, now has 10
Processor 1 has data 3
Processor 1 doubling the data, now has 6
Processor 0 has data: 2 6 10 14
_
60
Jonathan Dursi