MPI_Scatter - 发送2D数组的列

时间:2011-04-01 10:41:23

标签: c mpi

我想发送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发送的数据?

3 个答案:

答案 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的调用,但至少你能够轻松地按列访问数据。然后通过使用循环

将这些数据传递给相应的过程是一种简单的方法