这与这个问题非常相似:How to MPI_Gatherv columns from processor, where each process may send different number of columns。问题是列在内存中不是连续的,所以你必须玩弄。
在 C 语言中总是如此,缺少真正的多维数组,您必须对内存布局稍加小心。我相信在 C 中,静态声明的数组就像
float a[nrows][ncols]
在内存中是连续的,所以你现在应该没问题。但是,请注意,一旦您进行动态分配,情况将不再如此;您必须一次分配所有数据以确保获得连续数据,例如
float **floatalloc2d(int n, int m) {
float *data = (float *)malloc(n*m*sizeof(float));
float **array = (float **)calloc(n*sizeof(float *));
for (int i=0; i<n; i++)
array[i] = &(data[i*m]);
return array;
}
float floatfree2d(float **array) {
free(array[0]);
free(array);
return;
}
/* ... */
float **a;
nrows = 3;
ncols = 2;
a = floatalloc2d(nrows,ncols);
但我认为你现在还好。
现在您已经以一种或另一种方式拥有了二维数组,您必须创建您的类型。如果您只发送一列,您描述的类型就可以了;但这里的技巧是,如果您要发送多列,则每列仅从前一列的开头开始浮动,即使列本身几乎跨越整个数组!因此,您需要移动类型的上限才能使其正常工作:
MPI_Datatype col, coltype;
MPI_Type_vector(nrows,
1,
ncols,
MPI_FLOAT,
&col);
MPI_Type_commit(&col);
MPI_Type_create_resized(col, 0, 1*sizeof(float), &coltype);
MPI_Type_commit(&coltype);
会做你想做的事。请注意,receiving 进程将具有与 sending 进程不同的类型,因为它们存储的列数较少;所以元素之间的步幅更小。
最后,你现在可以做散布了,
MPI_Comm_size(MPI_COMM_WORLD,&size);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
if (rank == 0) {
a = floatalloc2d(nrows,ncols);
sendptr = &(a[0][0]);
} else {
sendptr = NULL;
}
int ncolsperproc = ncols/size; /* we're assuming this divides evenly */
b = floatalloc(nrows, ncolsperproc);
MPI_Datatype acol, acoltype, bcol, bcoltype;
if (rank == 0) {
MPI_Type_vector(nrows,
1,
ncols,
MPI_FLOAT,
&acol);
MPI_Type_commit(&acol);
MPI_Type_create_resized(acol, 0, 1*sizeof(float), &acoltype);
}
MPI_Type_vector(nrows,
1,
ncolsperproc,
MPI_FLOAT,
&bcol);
MPI_Type_commit(&bcol);
MPI_Type_create_resized(bcol, 0, 1*sizeof(float), &bcoltype);
MPI_Type_commit(&bcoltype);
MPI_Scatter (sendptr, ncolsperproc, acoltype, &(b[0][0]), ncolsperproc, bcoltype, 0, MPI_COMM_WORLD);