【MPI學習7】MPI並行程序設計模式:MPI的進程組和通信域


基於都志輝老師MPI編程書中的第15章內容。

通信域是MPI的重要概念:MPI的通信在通信域的控制和維護下進行 → 所有MPI通信任務都直接或間接用到通信域這一參數 → 對通信域的重組和划分可以方便實現任務的划分

 

(1)通信域(communicator)是一個綜合的通信概念。其包括上下文(context),進程組(group),虛擬處理器拓撲(topology)。其中進程組是比較重要的概念,表示通信域中所有進程的集合。一個通信域對應一個進程組。

 

(2)進程(process)與進程組(group)的關系。每個進程是客觀上唯一的(一個進程對應一個pid號);同一個進程可以屬於多個進程組(每個進程在不同進程組中有個各自的rank號);同一個進程可以屬於不同的進程組,因此也可以屬於不同的通信域。

 

(3)通信域產生的方法。根據看過的資料,大概有三種方法,先簡要了解路子即可:

  a. 在已有通信域基礎上划分獲得:MPI_Comm_split(MPI_Comm comm, int color, int key, MPI_Comm *newcomm)  

   b. 在已有通信域基礎上復制獲得:MPI_Comm_dup(MPI_Comm comm, MPI_Comm *newcomm)

     c. 在已有進程組的基礎上創建獲得:MPI_Comm_create(MPI_Comm comm, MPI_Group group, MPI_Comm *newcomm)

 

(4)進程組產生的方法。進程組(group)可以當成一個集合的概念,可以通過“子、交、並、補”各種方法。所有進程組產生的方法都可以套到集合的各種運算,用到的時候現看函數就可以了。

 

(5)“當前進程”與“通信域產生函數”。如果在已有進程組的基礎上創建新的通信域(即(3)中c方法),則newcomm有兩種結果:如果調用MPI_Comm_create的當前進程在group中,則newcomm就是新產生的通信域對象;如果調用MPI_Comm_create的當前進程不在group中,則newcomm就是MPI_COMM_NULL。由於MPI是多進程編程,類似“當前進程”與“通信域產生函數”這種情況會比較頻繁的出現,在設計思路上要適應並行編程這種改變。

 

(6)不同通信域間互不干擾。“互不干擾”嚴格來說並不完全正確,這里想說的意思是:同一個進程,可以屬於不同的通信域;同一個進程可以同時參與不同通信域的通信,互不干擾。

 

 

下面通過一個例子來感受一下進程組和通信域在MPI多進程任務划分和處理上的應用。

代碼做的事情如下:

(1)共有6個進程,在MPI_COMM_WORLD中的編號分別是{0,1,2,3,4,5}。

(2)將{1,3,5}進程形成一個新的通信域comm1;將編號為{0,2,4}的進程生成一個新的通信域comm2

(3)在comm1中執行MAX歸約操作;在comm2中執行MIN歸約操作;在MPI_COMM_WORLD中執行SUM歸約操作

(4)顯示各個通信域中歸約操作的結果

具體代碼如下:

 

 1 #include "mpi.h"
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 
 5 #define LEN 5
 6 
 7 int main(int argc, char *argv[])  8 {  9     MPI_Init(&argc, &argv); 10     int world_rank, world_size; 11     MPI_Comm_rank(MPI_COMM_WORLD, &world_rank); 12     MPI_Comm_rank(MPI_COMM_WORLD, &world_size); 13 
14  MPI_Group world_group; 15     MPI_Comm_group(MPI_COMM_WORLD, &world_group); 16 
17     int n = 3; 18     const int ranks[3] = {1,3,5}; 19     const int ori1[1] = {1}; 20     const int ori2[1] = {0}; 21     int root1, root2; 22 
23     // 從world_group進程組中構造出來兩個進程組
24  MPI_Group group1, group2; 25     MPI_Group_incl(world_group, n, ranks, &group1); 26     MPI_Group_excl(world_group, n, ranks, &group2); 27     // 根據group1 group2分別構造兩個通信域
28  MPI_Comm comm1, comm2; 29     MPI_Comm_create(MPI_COMM_WORLD, group1, &comm1); 30     MPI_Comm_create(MPI_COMM_WORLD, group2, &comm2); 31 
32     // 維護發送緩沖區和接受緩沖區
33     int i; 34     double *sbuf, *rbuf1, *rbuf2, *rbuf3; 35     sbuf = malloc(LEN*sizeof(double)); 36     rbuf1 = malloc(LEN*sizeof(double)); 37     rbuf2 = malloc(LEN*sizeof(double)); 38     rbuf3 = malloc(LEN*sizeof(double)); 39     srand(world_rank*100); 40     for(i=0; i<LEN; i++) sbuf[i] = (1.0*rand()) / RAND_MAX; 41     fprintf(stderr,"rank %d:\t", world_rank); 42     for(i=0; i<LEN; i++) fprintf(stderr,"%f\t",sbuf[i]); 43     fprintf(stderr,"\n"); 44     MPI_Group_translate_ranks(world_group, 1, ori1, group1, &root1); 45     MPI_Group_translate_ranks(world_group, 1, ori2, group2, &root2); 46     // MPI_COMM_WORLD comm1 comm2分別執行不同的歸約操作
47     if (MPI_COMM_NULL!=comm1) { // comm1
48  MPI_Reduce(sbuf, rbuf1, LEN, MPI_DOUBLE, MPI_MAX, root1, comm1); 49         int rank_1; 50         MPI_Comm_rank(comm1, &rank_1); 51         if (root1==rank_1) { 52             fprintf(stderr,"MAX:\t"); 53             for(i=0; i<LEN; i++) fprintf(stderr,"%f\t",rbuf1[i]); 54             fprintf(stderr,"\n"); 55  } 56  } 57     else if (MPI_COMM_NULL!=comm2) { // comm2
58  MPI_Reduce(sbuf, rbuf2, LEN, MPI_DOUBLE, MPI_MIN, root2, comm2); 59         int rank_2; 60         MPI_Comm_rank(comm2, &rank_2); 61         if (root2==rank_2) { 62             fprintf(stderr,"MIN:\t"); 63             for(i=0; i<LEN; i++) fprintf(stderr,"%f\t",rbuf2[i]); 64             fprintf(stderr,"\n"); 65  } 66  } 67     MPI_Reduce(sbuf, rbuf3, LEN, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); // MPI_COMM_WORLD 
68     if (0==world_rank) { 69         fprintf(stderr,"SUM:\t"); 70         for(i=0; i<LEN; i++) fprintf(stderr,"%f\t",rbuf3[i]); 71         fprintf(stderr,"\n"); 72  } 73     // 清理進程組和通信域
74     if(MPI_GROUP_NULL!=group1) MPI_Group_free(&group1); 75     if(MPI_GROUP_NULL!=group2) MPI_Group_free(&group2); 76     if(MPI_COMM_NULL!=comm1) MPI_Comm_free(&comm1); 77     if(MPI_COMM_NULL!=comm2) MPI_Comm_free(&comm2); 78  MPI_Finalize(); 79 }

 

 

代碼執行結果如下:

 

可以看到:

a. MIN歸約操作針對的是{0,2,4}

b. MAX歸約操作針對的是{1,3,5}

c. SUM歸約操作針對的是{0,1,2,3,4,5}

d. SUM與MIN或MAX歸約操作在時間上可能是重疊的,參與歸約操作的進程也有重疊,但在結果上沒有互相干擾。

 

(7)組間通信域不同的通信域之間也可以通信,核心的操作是需要構造一個新的通信域類型——組間通信域。與一般的通信域不同,組間通信域包含兩個進程組:本地進程組,遠程進程組。通過組間通信域可以實現上述兩個不同進程組內進程之間的通信。組間通信域的創建,需要在本地組和遠程組中的相關進程中都調用創建語句,而且創建語句的參數中local_leader和remote_leader還是對稱的。

 

 1 #include "mpi.h"
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 
 5 int main(int argc, char *argv[])  6 {  7     MPI_Comm myComm; // 標示本地子組的組內通信域
 8     MPI_Comm myFirstComm; // 組間通信域
 9     MPI_Comm mySecondComm; // 組間通信域
10     int color; // split用到的key
11     int rank; 12 
13     MPI_Init(&argc, &argv); 14     MPI_Comm_rank(MPI_COMM_WORLD, &rank); 15 
16     // 划分子通信域 17     // split是如何划分的 翻閱了英文的mpi tutorial教程 18     // 通過split函數中第三個參數來控制 當前進程在新的通信域中的新rank值大小
19     color = rank % 3; 20     MPI_Comm_split(MPI_COMM_WORLD, color, rank, &myComm); 21 
22     // 建立組間通信域 23     // 需要確定的問題是: 24     // 1. A1和A2構造的是01之間的通信域 A1的local leader和remote leader與A2的local leader和remote leader是不是互相對應的 25     // 2. 同理 B1和B2構造的是12之間的組間通信域 local leader和remote leader是否也是互相對應的 26     // 這是可以保證的 通過MPI_Comm_split語句中的第三個參數來保證
27     if (0==color) { 28         // 01之間的組間通信域 29         // 1. 本地組的leader是0 30         // 2. remote組的leader在MPI_COMM_WORLD中的rank是1 31         // 3. tag是1 (tag起到什么作用?) 32         // 4. 組間通信域存在myFirstComm中
33         MPI_Intercomm_create(myComm, 0, MPI_COMM_WORLD, 1, 1, &myFirstComm); // A1
34  } 35     else if (1==color) { 36         // 01之間的組間通信域 37         // 1. 本地組的leader是0 (本地組leader0應該是MPI_COMM_WORLD中的1 這是如何保證的?) 38         // 2. 同理, MPI_COMM_WORLD中的0應該是color=0那個組中rank為0的進程 這是如何保證的?
39         MPI_Intercomm_create(myComm, 0, MPI_COMM_WORLD, 0, 1, &myFirstComm); // A2 40         // 12之間的組間通信域
41         MPI_Intercomm_create(myComm, 0, MPI_COMM_WORLD, 2, 12, &mySecondComm); // B1
42  } 43     else if (2==color) { 44         // 21之間的組間通信域
45         MPI_Intercomm_create(myComm, 0, MPI_COMM_WORLD, 1, 12, &myFirstComm); // B2
46  } 47 
48     if (0==color || 2==color) { 49         MPI_Comm_free(&myFirstComm); 50  } 51     else if (1==color) { 52         MPI_Comm_free(&myFirstComm); 53         MPI_Comm_free(&mySecondComm); 54  } 55  MPI_Finalize(); 56 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM