回答

2

如果你想收集每個實例的最高值,那麼MPI_Gather()是正確的選擇。

如果你想收集所有實例的100個最高值(例如100個最高值不超過100個值),那麼我不認爲有一個「本地」的方式來實現這一目標。 /*當你寫list,我希望你的真正用意array */

這樣說,你可以以創建在兩個數組起作用的操作,然後與預先定義的操作調用MPI_Reduce()使用MPI_Op_create()

+0

是的,我想收集所有實例的100個值,和是的,他們是陣列。我只是想暗示他們已經排序。我會研究op_create,謝謝。恥辱沒有更直接的方式... –

2

吉爾的建議是一個非常優雅的一個,所以我想我會寫一個簡單的例子代碼,這將使用戶定義操作的極好的鍛鍊對於那些學習MPI。

請注意,我濫用了用戶定義操作的「len」參數的含義。這意味着要減少的數量和不是每個減少的規模。換句話說,LEN = 5應該意味着要對每個進程5對獨立的列表進行排序,而不是每個進程都有長度爲5的一個列表要解決這個問題就需要定義一個完整的列表中的新數據類型的MPI適當(例如MPI_Type_contiguous),但我現在無法正常工作。

但是,即使是這種技術上不正確的代碼也說明了基本方法。

示例輸出用於長度爲5的列表上3個過程是:

rank 0, mysortedlist[0] = 12 
rank 0, mysortedlist[1] = 9 
rank 0, mysortedlist[2] = 6 
rank 0, mysortedlist[3] = 3 
rank 0, mysortedlist[4] = 0 

rank 2, mysortedlist[0] = 14 
rank 2, mysortedlist[1] = 11 
rank 2, mysortedlist[2] = 8 
rank 2, mysortedlist[3] = 5 
rank 2, mysortedlist[4] = 2 

rank 1, mysortedlist[0] = 13 
rank 1, mysortedlist[1] = 10 
rank 1, mysortedlist[2] = 7 
rank 1, mysortedlist[3] = 4 
rank 1, mysortedlist[4] = 1 

rank 0, sortedlist[0] = 14 
rank 0, sortedlist[1] = 13 
rank 0, sortedlist[2] = 12 
rank 0, sortedlist[3] = 11 
rank 0, sortedlist[4] = 10 

下面的代碼。

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

#include <mpi.h> 

#define N 5 

void mergesortint(void *vinvec, void *vinoutvec, int *n, MPI_Datatype *type); 
void mergelist(int *merge, int *a, int *b, int n); 

int main(void) 
{ 
    int i; 

    // local sorted list 

    int mysortedlist[N]; 

    // global sorted list 

    int sortedlist[N]; 

    MPI_Comm comm; 

    MPI_Op MPI_MERGESORT; 

    // int rank, size; 

    int size, rank; 

    comm = MPI_COMM_WORLD; 

    MPI_Init(NULL, NULL); 

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

    // Register new reduction operation 

    MPI_Op_create(mergesortint, 1, &MPI_MERGESORT); 

    // Generate sorted lists on each rank 

    for (i=0; i < N; i++) 
    { 
     mysortedlist[i] = rank+size*(N-i-1); 
     sortedlist[i] = -1; 
    } 

    for (i=0; i < N; i++) 
    { 
     printf("rank %d, mysortedlist[%d] = %d\n", rank, i, mysortedlist[i]); 
    } 
    printf("\n"); 

    // Perform reduction to rank 0 

    MPI_Reduce(mysortedlist, sortedlist, N, MPI_INT, MPI_MERGESORT, 0, comm); 

    if (rank == 0) 
    { 
     for (i=0; i < N; i++) 
     { 
      printf("rank %d, sortedlist[%d] = %d\n", rank, i, sortedlist[i]); 
     } 
     printf("\n"); 
    } 

    MPI_Finalize(); 

    return 0; 
} 


void mergesortint(void *vinvec, void *vinoutvec, int *n, MPI_Datatype *type) 
{ 
    int i; 
    int nvec = *n; 

    int *invec = (int *) vinvec; 
    int *inoutvec = (int *) vinoutvec; 
    int *mergevec = (int *) malloc(nvec*sizeof(int)); 

    mergelist(mergevec, invec, inoutvec, nvec); 

    for (i=0; i < nvec; i++) 
    { 
     inoutvec[i] = mergevec[i]; 
    } 

    free(mergevec); 
} 


void mergelist(int *merge, int *a, int *b, int n) 
{ 
    int i, ia, ib; 

    ia = 0; 
    ib = 0; 

    for (i=0; i < n; i++) 
    { 
     if (a[ia] > b[ib]) 
     { 
      merge[i] = a[ia]; 
      ia++; 
     } 
     else 
     { 
      merge[i] = b[ib]; 
      ib++; 
     } 
    } 
} 
0

下面是完整的代碼,多個列表的工作原理,即「數」參數MPI_Reduce()是正確解釋爲單個列表的數量,而不是每個列表的長度。雖然列表長度N是主一個常數,歸約運算是更一般的,並計算從該列表類型程度的長度。

這裏有4個進程的輸出長度爲5的3名名單:

[email protected]> mpirun -n 4 ./mergesortlist 

rank 1, mysortedlist[0] = 17 117 217 
rank 1, mysortedlist[1] = 13 113 213 
rank 1, mysortedlist[2] = 9 109 209 
rank 1, mysortedlist[3] = 5 105 205 
rank 1, mysortedlist[4] = 1 101 201 

rank 2, mysortedlist[0] = 18 118 218 
rank 2, mysortedlist[1] = 14 114 214 
rank 2, mysortedlist[2] = 10 110 210 
rank 2, mysortedlist[3] = 6 106 206 
rank 2, mysortedlist[4] = 2 102 202 

rank 3, mysortedlist[0] = 19 119 219 
rank 3, mysortedlist[1] = 15 115 215 
rank 3, mysortedlist[2] = 11 111 211 
rank 3, mysortedlist[3] = 7 107 207 
rank 3, mysortedlist[4] = 3 103 203 

rank 0, mysortedlist[0] = 16 116 216 
rank 0, mysortedlist[1] = 12 112 212 
rank 0, mysortedlist[2] = 8 108 208 
rank 0, mysortedlist[3] = 4 104 204 
rank 0, mysortedlist[4] = 0 100 200 

rank 0, sortedlist[0] = 19 119 219 
rank 0, sortedlist[1] = 18 118 218 
rank 0, sortedlist[2] = 17 117 217 
rank 0, sortedlist[3] = 16 116 216 
rank 0, sortedlist[4] = 15 115 215 

和下面的代碼:

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

#include <mpi.h> 

#define NUMLIST 3 // Number of distinct lists (of integers) 
#define N 5  // Length of each list 

void mergesortlist(void *vinvec, void *vinoutvec, int *n, MPI_Datatype *type); 
void mergelist(int *merge, int *a, int *b, int n); 

int main(void) 
{ 
    int i, ilist; 

    // local sorted list 

    int mysortedlist[NUMLIST][N]; 

    // global sorted list 

    int sortedlist[NUMLIST][N]; 

    MPI_Comm comm; 

    MPI_Datatype MPI_LIST; 
    MPI_Op MPI_MERGELIST; 

    int size, rank; 

    comm = MPI_COMM_WORLD; 

    MPI_Init(NULL, NULL); 

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

    // Define datatype appropriate for a single array of N integers 

    MPI_Type_contiguous(N, MPI_INT, &MPI_LIST); 
    MPI_Type_commit(&MPI_LIST); 

    // Register new reduction operation to merge two sorted lists 

    MPI_Op_create(mergesortlist, 1, &MPI_MERGELIST); 

    // Generate sorted lists on each rank 

    for (i=0; i < N; i++) 
    { 
     for (ilist=0; ilist < NUMLIST; ilist++) 
     { 
     mysortedlist[ilist][i] = rank+size*(N-i-1) + 100*ilist; 
     sortedlist[ilist][i] = -1; 
     } 
    } 

    for (i=0; i < N; i++) 
    { 
    printf("rank %d, mysortedlist[%d] =", rank, i); 

    for (ilist=0; ilist < NUMLIST; ilist++) 
     { 
     printf(" %3d", mysortedlist[ilist][i]); 
     } 
    printf("\n"); 
    } 

    printf("\n"); 

    // Perform reduction to rank 0 

    MPI_Reduce(mysortedlist, sortedlist, NUMLIST, MPI_LIST, MPI_MERGELIST, 
     0, comm); 

    if (rank == 0) 
    { 
     for (i=0; i < N; i++) 
     { 
     printf("rank %d, sortedlist[%d] =", rank, i); 

     for (ilist=0; ilist < NUMLIST; ilist++) 
     { 
      printf(" %3d", sortedlist[ilist][i]); 
     } 
     printf("\n"); 
     } 

     printf("\n"); 
    } 

    MPI_Finalize(); 

    return 0; 
} 


void mergesortlist(void *vinvec, void *vinoutvec, int *n, MPI_Datatype *type) 
{ 
    MPI_Aint lb, listextent, intextent; 

    int i, ilist; 
    int nvec, nlist; 

    int *invec = (int *) vinvec; 
    int *inoutvec = (int *) vinoutvec; 

    // the count is the number of individual lists 

    nlist = *n; 

    // Infer length of each list from the extents 
    // Should really check "type" is valid, i.e. a contiguous block of ints 

    MPI_Type_get_extent(MPI_INT, &lb, &intextent); 
    MPI_Type_get_extent(*type, &lb, &listextent); 

    nvec = listextent/intextent; 

    // Need a temporary as "mergelist" does not work in-place 

    int *mergevec = (int *) malloc(nvec*sizeof(int)); 

    // Merge each of the "nlist" lists in turn 

    for (ilist=0; ilist < nlist; ilist++) 
    { 
     mergelist(mergevec, &invec[ilist*nvec], &inoutvec[ilist*nvec], nvec); 

     for (i=0; i < nvec; i++) 
     { 
     inoutvec[ilist*nvec+i] = mergevec[i]; 
     } 
    } 

    free(mergevec); 
} 


void mergelist(int *merge, int *a, int *b, int n) 
{ 
    int i, ia, ib; 

    ia = 0; 
    ib = 0; 

    for (i=0; i < n; i++) 
    { 
     if (a[ia] > b[ib]) 
     { 
      merge[i] = a[ia]; 
      ia++; 
     } 
     else 
     { 
      merge[i] = b[ib]; 
      ib++; 
     } 
    } 
}