MPI接收多个部分

时间:2013-08-05 13:47:41

标签: c++ mpi

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

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?

2 个答案:

答案 0 :(得分:1)

我在MPI中直接知道没有任何东西可以让你这样做,虽然可能会有一些令人讨厌的指针魔法可以让它发挥作用。一般来说,如果你想以这样的方式做事,就可以做得更干净。

另一个不是你的问题的直接答案,但你可能不知道的是你上面的三行命令可以使用MPI_SENDRECV组合成一个。试试这一行:

MPI_Sendrecv(snd_buff, snd_size, MPI_DOUBLE, snd_p, 0, 
             rcv_buff, rcv_size, MPI_DOUBLE, rcv_p, 0, 
             world, &status);

答案 1 :(得分:1)

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

#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接收到一个大的临时缓冲区并手动解压缩到不同的缓冲区。