通常,当我想向下一个处理器发送缓冲区并从上一个处理器接收另一个缓冲区时,我使用以下命令:

MPI_Irecv(rcv_buff,rcv_size,
        MPI_DOUBLE,rcv_p,0,world,
        &request);
MPI_Send(snd_buff,snd_size,
        MPI_DOUBLE,snd_p,0,world);
MPI_Wait(&request,&status);

假设我要将rcv_buff的第一个rcv_size0元素放入array0,将其余的(rcv_size1元素)放入array1,其中:
rcv_size1=rcv_size-rcv_size0;

通常我要做的是首先在此处创建一个类似rcv_buff的虚拟数组,然后开始将值复制到array0和array1。我的问题是,MPI中是否有任何方法可以接收两个或多个序列中的已发送字节?例如直接在array0中接收第一个size0元素,在array1中接收其余元素?

最佳答案

您可以通过创建特定于该对缓冲区的类型来将其接收到两个缓冲区中:

#include <stdio.h>
#include <mpi.h>
#include <stdlib.h>

int recv_split(const int total, const int src, const int tag,
               double *buffA, const int sizeA, double *buffB) {

    if (total <= 0)    return -1;
    if (sizeA > total) return -1;
    if (buffA == NULL) return -2;
    if (buffB == NULL) return -2;

    const int sizeB = total - sizeA;
    int blocksizes[2] = {sizeA, sizeB};
    MPI_Datatype types[2] = {MPI_DOUBLE, MPI_DOUBLE};
    MPI_Aint displacements[2], addrA, addrB;
    MPI_Datatype splitbuffer;
    MPI_Status status;

    displacements[0] = 0;
    MPI_Get_address(buffA, &addrA);
    MPI_Get_address(buffB, &addrB);
    displacements[1] = addrB - addrA;

    MPI_Type_create_struct(2, blocksizes, displacements, types, &splitbuffer);
    MPI_Type_commit(&splitbuffer);

    MPI_Recv(buffA, 1, splitbuffer, src, tag, MPI_COMM_WORLD, &status);

    MPI_Type_free(&splitbuffer);

    return 0;
}


int main(int argc, char **argv) {
    int rank, size;

    MPI_Init(&argc, &argv);

    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    const int sendSize = 15;
    const int tag = 1;

    if (rank == 0 && size >= 2) {
        double sendbuff[sendSize];
        for (int i=0; i<sendSize; i++)
            sendbuff[i] = 1.*i;

        MPI_Send(sendbuff, sendSize, MPI_DOUBLE, 1, tag, MPI_COMM_WORLD);
    }
    if (rank == 1) {
        const int buffLen = 12;
        const int recvIntoA = 10;
        double buffA[buffLen];
        double buffB[buffLen];

        for (int i=0; i<buffLen; i++) {
            buffA[i] = buffB[i] = -1.;
        }

        recv_split(sendSize, 0, tag, buffA, recvIntoA, buffB);

        printf("---Buffer A--\n");
        for (int i=0; i<buffLen; i++)
            printf("%5.1lf ", buffA[i]);

        printf("\n---Buffer B--\n");
        for (int i=0; i<buffLen; i++)
            printf("%5.1lf ", buffB[i]);
        printf("\n");
    }

    MPI_Finalize();
    return 0;

}

编译并运行给出
$ mpicc -o recvsplit recvsplit.c  -std=c99
$ mpirun -np 2 ./recvsplit
---Buffer A--
  0.0   1.0   2.0   3.0   4.0   5.0   6.0   7.0   8.0   9.0  -1.0  -1.0
---Buffer B--
 10.0  11.0  12.0  13.0  14.0  -1.0  -1.0  -1.0  -1.0  -1.0  -1.0  -1.0

请注意,此类型仅对这对缓冲区有效;不同的线对通常具有不同的相对位移。当然,您还可以始终使用一个自己的代码或 MPI_Unpack 接收一个大的暂存缓冲区并手动将其解压缩到不同的缓冲区中。

10-04 14:30