はい、特定のタスクのためにこれを行うことができます。しかし、あなたはすべきではありません。
これをどのように実装するかを検討してください。開始部分はデータを配布し、終了部分は答えを返します。
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <mpi.h>
typedef struct state_t {
int globaln;
int localn;
int *locals;
int *offsets;
double *localin;
double *localout;
double (*map)(double);
} state;
state *begin_parallel_mapandsum(double *in, int n, double (*map)(double)) {
state *s = malloc(sizeof(state));
s->globaln = n;
s->map = map;
/* figure out decomposition */
int size, rank;
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
s->locals = malloc(size * sizeof(int));
s->offsets = malloc(size * sizeof(int));
s->offsets[0] = 0;
for (int i=0; i<size; i++) {
s->locals[i] = (n+i)/size;
if (i < size-1) s->offsets[i+1] = s->offsets[i] + s->locals[i];
}
/* allocate local arrays */
s->localn = s->locals[rank];
s->localin = malloc(s->localn*sizeof(double));
s->localout = malloc(s->localn*sizeof(double));
/* distribute */
MPI_Scatterv( in, s->locals, s->offsets, MPI_DOUBLE,
s->localin, s->locals[rank], MPI_DOUBLE,
0, MPI_COMM_WORLD);
return s;
}
double end_parallel_mapandsum(state **s) {
double localanswer=0., answer;
/* sum up local answers */
for (int i=0; i<((*s)->localn); i++) {
localanswer += ((*s)->localout)[i];
}
/* and get global result. Everyone gets answer */
MPI_Allreduce(&localanswer, &answer, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
free( (*s)->localin );
free( (*s)->localout );
free( (*s)->locals );
free( (*s)->offsets );
free( (*s) );
return answer;
}
int main(int argc, char **argv) {
int rank;
double *inputs;
double result;
int n=100;
const double pi=4.*atan(1.);
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
if (rank == 0) {
inputs = malloc(n * sizeof(double));
for (int i=0; i<n; i++) {
inputs[i] = 2.*pi/n*i;
}
}
state *s=begin_parallel_mapandsum(inputs, n, sin);
for (int i=0; i<s->localn; i++) {
s->localout[i] = (s->map)(s->localin[i]);
}
result = end_parallel_mapandsum(&s);
if (rank == 0) {
printf("Calculated result: %lf\n", result);
double trueresult = 0.;
for (int i=0; i<n; i++) trueresult += sin(inputs[i]);
printf("True result: %lf\n", trueresult);
}
MPI_Finalize();
}
この絶え間ない分散/収集は、いくつかの数値を合計すると通信の負担が大きく、分散メモリ コンピューティング モデル全体とは対照的です。
最初の概算では、共有メモリ アプローチ (OpenMP、pthreads、IPP など) は、計算を高速にスケーリングすることに関するものです。メモリの同じチャンクでより多くのプロセッサを投入することについて。一方、分散メモリ コンピューティングとは、計算をより大きくスケーリングすることです。単一のコンピュータで見られるよりも多くのリソース、特にメモリを使用することについて。MPI を使用する大きな利点は、どのノードのメモリにも収まらない問題セットを扱う場合です。そのため、分散メモリ コンピューティングを行う場合、すべてのデータを 1 つの場所に保持することは避けます。
MPI オンノードを使用してすべてのプロセッサを使用する場合でも、この基本的なアプローチを念頭に置いておくことが重要です。上記のスキャッター/ギャザー アプローチは、パフォーマンスを低下させるだけです。より慣用的な分散メモリ コンピューティングのアプローチは、プログラムのロジックが既にデータを分散しているというものです。つまり、ループの最初の段階でbegin_parallel_region
、end_parallel_region
以上のコードが既にループ上のコードに組み込まれています。次に、すべてのループは
for( int i=0 ; i<localn ; i++ )
{
s = s + sin(x[i]);
}
タスク間でデータを交換する必要がある場合 (または結果を減らす場合など) は、MPI 関数を呼び出してそれらの特定のタスクを実行します。