我有一个使用MPI库的C程序。我初始化了一个动态2-D数组,其中维度(行和列)是从进程根的stdin
读取的。
当我尝试在其他进程中循环分发元素(列)时,我没有取得任何进展。我使用MPI_Scatter
将列分发给数组中的其他进程。在那里,我利用派生数据类型MPI_Type_vector
作为二维数组。
当然,它只将第一列分配给进程的本地1-D数组。所以对于其余部分,我将MPI_Scatter
置于for循环中,现在我已经分配了所有列,但仅适用于进程数和矩阵维度相等的情况。 如何使用MPI_Scatter
向流程分发多个列?
到目前为止,我怀疑这是解决问题的最佳方法,因为必须有更好的方式来减少沟通。
对于矩阵使用1-D阵列而不是2-D阵列是否更明智?
修改
经过一番思考后,很明显,如果我使用for循环,派生数据类型MPI_Type_vector
就变得不必要了。这表明for循环并没有给我带来任何进一步的影响。
for(i=0 ;i<m; i++)
MPI_Scatter(&(array[i][0]), 1, ub_mpi_t, &local_array[i], 1, MPI_DOUBLE, 0,
MPI_COMM_WORLD) ;
答案 0 :(得分:1)
好的,让我们先尝试一下这个简单的案例 - 每个进程只有一列。以下是我对上述内容的略微编辑版本;我想指出的差异只是我们改变了数组A的分配方式,而我们只是使用了一种矢量数据类型:
#include <mpi.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
double **A = NULL ; /*2D array initialised on process 0 */
double *Adata = NULL;
double *sendbufptr = NULL;
int i,j ;
double *column ; /*1D array for column */
const int columnlen=6;
int my_rank, p ;
MPI_Datatype vector_mpi_t ;
MPI_Init(&argc,&argv) ;
MPI_Comm_rank(MPI_COMM_WORLD,&my_rank) ;
MPI_Comm_size(MPI_COMM_WORLD,&p) ;
/*initialise 2D array on process 0 and allocate memory*/
if(my_rank==0)
{
A = (double**)malloc(p*sizeof(double *)) ;
Adata = (double *)malloc(p*columnlen*sizeof(double));
for(i=0;i<p;i++)
A[i] = &(Adata[i*columnlen]);
for (i=0; i<p; i++)
for (j=0; j<columnlen; j++)
A[i][j] = i;
/* print 2D array to screen */
printf("Rank 0's 2D array:\n");
for(i=0;i<p;i++)
{
for(j=0;j<columnlen;j++)
printf( "%lf " , A[i][j]) ;
printf( "\n") ;
}
printf( "\n") ;
printf( "\n") ;
}
/* initialise and allocate memory for 1d column array on every process */
column = (double*)malloc(columnlen*sizeof(double)) ;
for(i=0;i<columnlen;i++)
{
column[i] = 0 ;
}
/*derived datatype for 2D array columns*/
MPI_Type_vector(columnlen,1,1,MPI_DOUBLE,&vector_mpi_t) ;
MPI_Type_commit(&vector_mpi_t);
sendbufptr = NULL;
if (my_rank == 0) sendbufptr=&(A[0][0]);
MPI_Scatter(sendbufptr, 1, vector_mpi_t, column, 1, vector_mpi_t, 0, MPI_COMM_WORLD);
/*print column on every process */
printf("Rank %d's column: \n", my_rank);
for(i=0;i<columnlen;i++)
{
printf( "%lf " , column[i]) ;
}
printf( "\n") ;
MPI_Finalize() ;
free(column);
free(Adata);
free(A);
return 0;
}
这里的关键是MPI_Scatter获取指向数据块的指针 - 而不是指针指针。所以它不会取消引用A [1]然后发送指向那里的东西,然后发送A [2]以及指向那里的东西等等。它期望一个连续的数据块。所以我们已经安排了A的数据在内存中的排列方式(请注意,这通常是数值计算的正确方法) - 它有一列数据,后面是下一列数据等。(虽然我打印数据的方式更像是行,但无论如何。)
另请注意,在MPI_Scatter调用中,我不能只使用&amp;(A [0] [0]),因为除了其中一个进程外,它只取消引用空指针。
从一列到几列非常简单;列数据结构从1d数组变为2d数组,如A所示。
#include <mpi.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
double **A = NULL ; /*2D array initialised on process 0 */
double *Adata = NULL;
double *sendbufptr = NULL;
int i,j ;
double **columns ; /*2D array for column */
double *columndata;
const int columnlen=6;
int ncolumns;
int my_rank, p ;
MPI_Datatype vector_mpi_t ;
MPI_Init(&argc,&argv) ;
MPI_Comm_rank(MPI_COMM_WORLD,&my_rank) ;
MPI_Comm_size(MPI_COMM_WORLD,&p) ;
ncolumns = 2*p;
/*initialise 2D array on process 0 and allocate memory*/
if(my_rank==0)
{
A = (double**)malloc(ncolumns*sizeof(double *)) ;
Adata = (double *)malloc(ncolumns*columnlen*sizeof(double));
for(i=0;i<ncolumns;i++)
A[i] = &(Adata[i*columnlen]);
for (i=0; i<ncolumns; i++)
for (j=0; j<columnlen; j++)
A[i][j] = i;
/* print 2D array to screen */
printf("Rank 0's 2D array:\n");
for(i=0;i<ncolumns;i++)
{
for(j=0;j<columnlen;j++)
printf( "%lf " , A[i][j]) ;
printf( "\n") ;
}
printf( "\n") ;
printf( "\n") ;
}
/* initialise and allocate memory for 1d column array on every process */
columndata = (double*)malloc((ncolumns/p)*columnlen*sizeof(double)) ;
columns = (double **)malloc((ncolumns/p)*sizeof(double *));
for(i=0;i<(ncolumns/p);i++)
{
columns[i] = &(columndata[i*columnlen]);
}
/*derived datatype for 2D array columns*/
MPI_Type_vector(columnlen,1,1,MPI_DOUBLE,&vector_mpi_t) ;
MPI_Type_commit(&vector_mpi_t);
sendbufptr = NULL;
if (my_rank == 0) sendbufptr=&(A[0][0]);
MPI_Scatter(sendbufptr, (ncolumns/p), vector_mpi_t, &(columns[0][0]), (ncolumns/p), vector_mpi_t, 0, MPI_COMM_WORLD);
/*print columns on every process */
printf("Rank %d's columns: \n", my_rank);
for(i=0;i<ncolumns/p;i++)
{
printf( "[%d]: ", my_rank) ;
for(j=0;j<columnlen;j++)
{
printf( "%lf " , columns[i][j]) ;
}
printf( "\n") ;
}
MPI_Finalize() ;
free(columns);
free(Adata);
free(A);
return 0;
}
然后,每个处理器的列数不同需要使用MPI_Scatterv而不是MPI_Scatter。
答案 1 :(得分:0)
我不确定我完全明白你要做什么,也不知道怎么做,所以这可能是不合适的:
看起来好像是在尝试在多个进程中分发2D数组的列。也许您有一个10列数组和4个进程,因此2个进程每个将获得3列,2个进程将分别获得2列?当然,进程0'自己得到'3列。
您采取的第一步是定义一个定义数组列的MPI_Type_vector。
接下来,在这里我对你使用MPI_Scatter感到有些困惑,为什么不简单地编写一个循环,将1,2,3,4,5,6,7,8,9,10列发送到进程0, 1,2,3,0,1,2,3,0,1(哦,先前已经安排接收过程有一个二维数组,以便在列到达时放入列)?
使用MPI_Scatter的问题在于,您(我认为)将相同数量的数据发送到每个接收进程,正如您所观察到的那样,如果进程数量不完全正确,则无法正常工作分成数组中的列数。如果你必须使用MPI_Scatter,那么你可能需要用额外的列填充数组,但这似乎有点无意义。
最后,您可以在1个语句中使用MPI_Type_create_subarray或MPI_Type_create_darray执行您想要的操作,但我没有使用这些内容的经验。