【问题标题】:How to send slice of a 3D array by using MPI?如何使用 MPI 发送 3D 数组的切片?
【发布时间】:2019-12-25 03:41:10
【问题描述】:

我有一个 3D 数组 Foo3D (50 x 100 x 100) 在等级 0 和 1 中。Foo3D 是这样分配的:

int nx = 50;
int ny = 100;
int nz = 100;
typedef int nRarray[100][50];
nRarray *Foo3D;
if ((Foo3D = (nRarray *)malloc((nx*ny*nz)*sizeof(int))) == 0) {fprintf(stderr,"malloc1 Fail \n"); return 1;}

我将一些数字分配给排名为 0 的 Foo3D,并将其保存到一个新的二维数组 (Foo2D) 中:

if (myrank == 0) {
for (int j = 0; j < ny; j++) {
 for (int k = 0; k < nz; k++) {

   Foo3D[0][j][k] = j + k;
   Foo2D[j][k] = Foo3D[0][j][k];
}
 } 
}

现在,我有兴趣将 Foo2D 发送到排名 1,并将其放在 Foo3D 中的位置。事实上,我知道我可以将Foo2D 发送到排名 1 为:

if (myrank == 0)
{
 MPI_Send(Foo2D,sizeof_Foo2D,MPI_INT,1,100,MPI_COMM_WORLD);
}
else if (myrank == 1)
{
 MPI_Recv(Foo2D,sizeof_Foo2D,MPI_INT,0,100,MPI_COMM_WORLD, &status);
}

然后将接收到的 rank 1 中的Foo2D 分配给它在Foo3D 中的位置为:

if (myrank == 1)
{
for (int j = 0; j < ny; j++) {
 for (int k = 0; k < nz; k++) {

   Foo3D[0][j][k] = Foo2D[j][k];
}
 } 
}

不使用此过程并将Foo2D 作为中间变量,是否可以将等级0 中的Foo3D 切片直接 发送到等级1 中的等效位置?事实上,我不想将整个 Foo3D 发送到排名 1,因为它是一个非常大的数组,我有兴趣只发送一部分到排名 1。

【问题讨论】:

  • 你的数组必须分配在连续的内存中,但你的 sn-p 没有显示它们是如何声明的。如果您需要更多帮助,请上传minimal reproducible example。
  • @GillesGouaillardet 完成。
  • 有些东西仍然丢失,这还不是minimal reproducible example。您的else if(...) 测试中也可能有错字。

标签: c++ mpi


【解决方案1】:

您将数组Foo3D 定义为int[nx][ny][nz]。因为 C/C++ 是行主要语言,表示为Foo3D[0][j][k] 的网格面元素在内存中实际上是连续的。

所以你可以简单地使用i=0发送面部:

if (myrank == 0) {
    MPI_Send(Foo3D, ny*nz, MPI_INT, 1, 100, MPI_COMM_WORLD);
}
else if (myrank == 1){
    MPI_Recv(Foo3D, ny*nz, MPI_INT, 0, 100, MPI_COMM_WORLD, &status);
}

另一方面,如果您想发送非连续数据不使用使用缓冲区 (Zero-Copy),您可以创建一个自定义 MPI 数据类型来表示您要复制的数据,并直接从源缓冲区发送,即使它在内存中不连续,MPI 也会读取您指定的数据。这可以使用MPI_Type_vector 来完成。

例如,如果要发送k=0的值,即网格面 Foo[i][j][0]。

首先,创建一个表示您要发送的网格面的数据类型。

// Create a data type and save its size
MPI_Datatype cubeface;
int cubefacesize;
MPI_Type_vector(nx*ny, 1, nz, MPI_INT, &cubeface);
MPI_Type_commit(&cubeface);
MPI_Type_size(cubeface, &cubefacesize);

然后,您可以使用以下方式发送和接收:

if (myrank == 0) {
    MPI_Send(Foo3D, 1, cubeface, 1, cubefacesize, MPI_COMM_WORLD);
} else if (myrank == 1) {
    MPI_Recv(Foo3D, 1, cubeface, 0, cubefacesize, MPI_COMM_WORLD, &status);
}

【讨论】:

  • 你的派生数据类型在 Fortran 中是正确的,但这里是 C。
  • @GillesGouaillardet 你的意思是行和主列数组?因为在 FORTRAN 中,数组是列主要的,但在 C 中,数组是行主要的,对吧?
  • @GillesGouaillardet 你是对的!谢谢你。我会更新我的答案。
  • @AloneProgrammer 是的,我相信这就是 Gilles 的意思。我已经相应地更新了答案。
猜你喜欢
  • 2013-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-12
  • 2012-03-19
  • 2013-03-07
相关资源
最近更新 更多