2013-08-05 71 views
2

通常當我想到緩衝器發送到下一個處理器和接收來自前一個另一個我使用下面的: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元件在陣列0和陣列1,其餘(rcv_size1元素),其中:

rcv_size1=rcv_size-rcv_size0; 

通常我做什麼,我第一次在這裏創建一個虛擬陣列像rcv_buff,然後開始複製值陣列0和陣列1。我的問題是,MPI有沒有辦法以兩個或多個序列接收發送的字節?例如直接接收array0中的第一個size0元素,其餘的則是array1?

回答

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手動將其解壓縮到一個大的分段緩衝區中並手動解壓縮到不同的緩衝區中。

+0

請注意,您可以使用其他類型,例如['Vector'](http://www.mcs.anl.gov/research/projects/mpi/www/www3/MPI_Type_vector.html),以避免重新定義基礎數據類型;我個人發現struct更清晰一些,但是YMMV。 –

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); 
+0

+1 for sendrecv;它很可能變成與「原始代碼」中的原始代碼非常相似的代碼,但它的代碼行數更少,並且對於那些第一次訪問代碼的代碼更加清晰。 –