2015-08-08 25 views
0

我試圖從主節點收集所有處理器(包括主節點)中不同長度的字符串到單個字符串(字符數組)中。這裏是原型MPI_Gatherv:如何使用MPI_Gatherv從不同的處理器(包括主節點)收集不同長度的字符串?

int MPI_Gatherv(const void *sendbuf, int sendcount, MPI_Datatype sendtype, 
      void *recvbuf, const int *recvcounts, const int *displs, 
      MPI_Datatype recvtype, int root, MPI_Comm comm)**. 

我無法定義諸如recvbufrecvcountsdispls一些參數。任何人都可以在C中爲此提供源代碼示例嗎?

+1

有使用['MPI_Gatherv()'](http://www.mpich.org/static/docs/v3的一些例子.1/www3/MPI_Gatherv.html)[mpi-forum](http://www.mpi-forum.org/docs/mpi-1.1/mpi-11-html/node70.html)。你可以調用'MPI_Gather()'來從數組'recvcounts'中的每個進程收集每個字符串的長度,計算位移爲'displs [0] = 0,displs [i] = displs [i-1] + recvcounts [i-1]',爲'recvbuf'分配足夠的空間,調用'MPI_Gatherv()',最後設置'recvbuf'的空終止字符以確保有效的可打印字符串。 – francis

回答

2

正如已經指出的,有很多使用MPI_Gatherv的例子,包括這裏的堆棧溢出;一個回答開始描述如何分散和收集工作,然後分散/聚集變種如何擴展,可以找到here。至關重要的是,對於更簡單的Gather操作,每個塊大小相同,MPI庫可以輕鬆地預先計算每個塊在最終編譯數組中的位置;在更普遍的collectv操作中,如果不太清楚,您可以選擇 - 實際上是要求 - 準確說明每個項目的起始位置。

這裏唯一的額外麻煩是你正在處理字符串,所以你可能不希望所有的東西都一起推進;你會需要額外的空格填充,當然最後還需要一個空終止符。

因此,讓我們說你有五道工序想發送的字符串:

Rank 0: "Hello" (len=5) 
Rank 1: "world!" (len=6) 
Rank 2: "Bonjour" (len=7) 
Rank 3: "le"  (len=2) 
Rank 4: "monde!" (len=6) 

你會想這是組裝成一個全球性的字符串:

Hello world! Bonjour le monde!\0 
      111111111122222222223 


recvcounts={5,6,7,2,6}; /* just the lengths */ 
displs = {0,6,13,21,24}; /* cumulative sum of len+1 for padding */ 

你可以看到,位移0 0和位移i等於(recvcounts [j]的+1)對於j的總和= 0..i-1:

i count[i] count[i]+1 displ[i] displ[i]-displ[i-1] 
    ------------------------------------------------------------ 
    0  5   6   0  
    1  6   7   6     6 
    2  7   8   13     7 
    3  2   3   21     8 
    4  6   7   24     3 

甲ND該真實直接地實現:

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

#define nstrings 5 
const char *const strings[nstrings] = {"Hello","world!","Bonjour","le","monde!"}; 

int main(int argc, char **argv) { 

    MPI_Init(&argc, &argv); 

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

    /* Everyone gets a string */  

    int myStringNum = rank % nstrings; 
    char *mystring = (char *)strings[myStringNum]; 
    int mylen = strlen(mystring); 

    printf("Rank %d: %s\n", rank, mystring); 

    /* 
    * Now, we Gather the string lengths to the root process, 
    * so we can create the buffer into which we'll receive the strings 
    */ 

    const int root = 0; 
    int *recvcounts = NULL; 

    /* Only root has the received data */ 
    if (rank == root) 
     recvcounts = malloc(size * sizeof(int)) ; 

    MPI_Gather(&mylen, 1, MPI_INT, 
       recvcounts, 1, MPI_INT, 
       root, MPI_COMM_WORLD); 

    /* 
    * Figure out the total length of string, 
    * and displacements for each rank 
    */ 

    int totlen = 0; 
    int *displs = NULL; 
    char *totalstring = NULL; 

    if (rank == root) { 
     displs = malloc(size * sizeof(int)); 

     displs[0] = 0; 
     totlen += recvcounts[0]+1; 

     for (int i=1; i<size; i++) { 
      totlen += recvcounts[i]+1; /* plus one for space or \0 after words */ 
      displs[i] = displs[i-1] + recvcounts[i-1] + 1; 
     } 

     /* allocate string, pre-fill with spaces and null terminator */ 
     totalstring = malloc(totlen * sizeof(char));    
     for (int i=0; i<totlen-1; i++) 
      totalstring[i] = ' '; 
     totalstring[totlen-1] = '\0'; 
    } 

    /* 
    * Now we have the receive buffer, counts, and displacements, and 
    * can gather the strings 
    */ 

    MPI_Gatherv(mystring, mylen, MPI_CHAR, 
       totalstring, recvcounts, displs, MPI_CHAR, 
       root, MPI_COMM_WORLD); 


    if (rank == root) { 
     printf("%d: <%s>\n", rank, totalstring); 
     free(totalstring); 
     free(displs); 
     free(recvcounts); 
    } 

    MPI_Finalize(); 
    return 0; 
} 

運行給出:

$ mpicc -o gatherstring gatherstring.c -Wall -std=c99 
$ mpirun -np 5 ./gatherstring 
Rank 0: Hello 
Rank 3: le 
Rank 4: monde! 
Rank 1: world! 
Rank 2: Bonjour 
0: <Hello world! Bonjour le monde!> 
+0

感謝所有... –

相關問題