2

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

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 中的其余元素?

4

2 回答 2

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);
于 2013-08-05T13:55:45.710 回答
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.

于 2013-08-05T16:04:32.167 回答