如何使用 MPI 发送 3D 数组的切片?

How to send slice of a 3D array by using MPI?

我有一个 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);
}

然后将接收到的第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。

您正在将数组 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), you can create a custom MPI datatype that represents the data you want to copy, and send directly from the source buffer, and MPI will read the data you specified even if it is non-contiguous in memory. This can be done using 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);
}