我想发送2D数组的列,每个列都是单独的进程。我现在有一个完整的2d阵列,我被MPI_Scatter困住了。如何将整列作为字段发送?
由于
修改
我有数组 - 浮动[100] [101]
我试图通过以下方式发送数组:
float send;
MPI_Scatter ((void *)a, n, MPI_FLOAT,(void *)&send , 1, MPI_INT,0, MPI_COMM_WORLD);
EDIT2:
我制作了新的type_vector:
MPI_Datatype newtype;
MPI_Type_vector(n, /* # column elements */
1, /* 1 column only */
n+1, /* skip n+1 elements */
MPI_FLOAT, /* elements are float */
&newtype); /* MPI derived datatype */
MPI_Type_commit(&newtype);
现在我试图将它发送到我的其他进程。矩阵由浮点数填充,我的矩阵是n x n + 1,因为测试是n = 5,所以它是矩阵5 x 6. Scatter的调用是什么以及我应该从其他进程的方面采取什么方法?我的意思是,如何获取由scatter发送的数据?
答案 0 :(得分:6)
这与此问题非常相似: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);
会做你想要的。请注意,接收进程的类型与发送进程的类型不同,因为它们存储的列数较少;因此元素之间的步幅较小。
最后,您现在可以进行分散,
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);
答案 1 :(得分:3)
这有很多问题,但你的主要问题是内存布局。在a
表示的内存位置,没有一个float
:只有float*
s指向内存中其他位置的float
的各种数组。由于这些数组不一定是连续的,因此不能对它们使用Scatter。
最简单的解决方案是将矩阵存储在一个数组中:
float a[100*101];
按照主要顺序填写。然后简单地像Scatter一样:
MPI_Scatter(a, 100*101, MPI_FLOAT, send, 10*101, MPI_FLOAT, 0, MPI_COMM_WORLD);
这假设您在10个进程之间进行分散,并且send
在每个进程中定义为float[10*101]
。请注意,在您发布的代码中,Scatter的4-6参数肯定存在缺陷。如果send
是一个数组,那么您不需要传递&send
(出于同样的原因,您不需要在第一个参数中传递&a
),并且您希望将您收到的数据项的数量和类型与您发送的内容相匹配。
答案 2 :(得分:0)
好吧,Scatter尝试以相等的比例发送它必须发送的数据。不幸的是,C中的数据以行方式存储,而不是按列存储。因此,您的调用将导致Scatter获取n个元素,然后发送每个进程m = n /(进程数)浮动。
这个问题的一个常见方法是创建一个新的MPI-vector数据类型(参见函数MPI_Type_vector),在这个数据类型中你可以克服C数组的行数据存储问题(因为你可以定义它之间的步幅)向量中的元素,这将是一行的长度。)
我没有以这种方式使用向量分散,所以我不确定这是否有助于Scatter的调用,但至少你能够轻松地按列访问数据。然后通过使用循环
将这些数据传递给相应的过程是一种简单的方法