gpt4 book ai didi

c - 二维数组从根到其他进程的 MPI 列循环分布

转载 作者:行者123 更新时间:2023-11-30 16:03:45 25 4
gpt4 key购买 nike

我有一个使用 MPI 库的 C 程序。我初始化了一个动态二维数组,其维度(行和列)是从进程根的 stdin 读取的。

当我尝试在其他进程之间循环分配元素(列)时,我没有取得任何进展。我使用 MPI_Scatter 将列分配给数组中的其他进程。在那里,我利用了二维数组的派生数据类型 MPI_Type_vector

当然,它只将第一列分配给进程的本地一维数组。因此,对于其余部分,我将 MPI_Scatter 放入 for 循环中,现在我已分配所有列,但仅限于进程数和矩阵维度相等的情况。 如何使用 MPI_Scatter 将多个列分配给一个进程?

到目前为止,我怀疑这是否是解决问题的最佳尝试,因为一定有更好的方法,更少的沟通。

使用一维数组代替二维数组作为矩阵是否更明智?

编辑:

经过一番思考,很明显,如果我使用 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) ;

最佳答案

好吧,让我们先尝试一下简单的情况——每个进程只有一列。以下是我对上面内容稍作编辑的版本;我想指出的差异只是我们改变了数组 A 的分配方式,并且我们只使用一种 vector 数据类型:

#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 接受一个指向数据 block 的指针,而不是指向指针的指针。因此,它不会取消引用 A[1],然后发送指向那里的内容,然后发送 A[2] 和指向那里的内容,等等。它需要一个连续的数据 block 。因此,我们已经安排了 A 的数据在内存中的布局方式(请注意,这通常是数值计算的正确方法)——它有一列数据,后面跟着下一列数据,等等(虽然我打印数据的方式更像是行,但无论如何。)

还要注意,在 MPI_Scatter 调用中,我不能只使用 &(A[0][0]),因为这会在除一个进程之外的所有进程中取消引用空指针。

从一栏到几栏非常简单;列数据结构从一维数组变成了像 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。

关于c - 二维数组从根到其他进程的 MPI 列循环分布,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3751141/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com