2014-03-29 45 views
1

說,我有8個進程。當我做以下事情時,MPU_COMM_WORLD通信器將被分解爲兩個通信器。帶有偶數ID的進程將屬於一個通信者,而具有奇數ID的進程將屬於另一個通信者。在MPI_Comm_split之後如何分發句柄?

color=myid % 2; 
MPI_Comm_split(MPI_COMM_WORLD,color,myid,&NEW_COMM); 
MPI_Comm_rank(NEW_COMM, &new_id); 

我的問題是這兩個傳播者的句柄在哪裏。分割之後,處理器的id將會變爲0 2 4 6 | 1 3 5 7.

現在,我的問題是:假設我想在一個特定的通信器中發送和接收,比如說那個託管偶數ids的那個,然後當我使用錯誤的通信器從0發送到2的消息時消息可能會在第二個通信器中結束,這是正確的嗎?提前謝謝澄清!

if(new_id < 2){ 

    MPI_Send(&my_num, 1, MPI_INT, 2 + new_id, 0, NEW_COMM); 
    MPI_Recv(&my_received, 1, MPI_INT, 2 + new_id, 0, NEW_COMM, MPI_STATUS_IGNORE);   

} 
else 
{ 
    MPI_Recv(&my_received, 1, MPI_INT, new_id - 2, 0, NEW_COMM, MPI_STATUS_IGNORE);   
    MPI_Send(&my_num, 1, MPI_INT, new_id - 2 , 0, NEW_COMM); 


} 

的完整代碼

#include <stdio.h> 
#include <stdlib.h> 
#include <mpi.h> 
#include <math.h> 
int main(argc,argv) 
int argc; 
char *argv[]; 

{ 
    int myid, numprocs; 
    int color,Zero_one,new_id,new_nodes; 
    MPI_Comm NEW_COMM; 
    MPI_Init(&argc,&argv); 
    MPI_Comm_size(MPI_COMM_WORLD,&numprocs); 
    MPI_Comm_rank(MPI_COMM_WORLD,&myid); 


    int my_num, my_received; 

     int old_id; 


    switch(myid){ 

     case 0: 
      my_num = 0; 
      old_id = 0; 

     break; 


     case 1: 
      my_num = 1; 
      old_id = 1; 

     break; 

     case 2: 
      my_num = 2; 
      old_id = 2; 

     break; 

     case 3: 
      my_num = 3; 
      old_id = 3; 

     break; 

     case 4: 
      my_num = 4; 
      old_id = 4; 

     break; 

     case 5: 
      my_num = 5; 
      old_id = 5; 

     break; 

     case 6: 
      my_num = 6; 
      old_id = 6; 

     break; 

     case 7: 
      my_num = 7; 
      old_id = 7; 

     break; 


    } 



    color=myid % 2; 
    MPI_Comm_split(MPI_COMM_WORLD,color,myid,&NEW_COMM); 
    MPI_Comm_rank(NEW_COMM, &new_id); 
    MPI_Comm_rank(NEW_COMM, &new_nodes); 



     // 0 1 2 3  4 5 6 7 //After splits we have these nums for 8 processors 
     // 2 3 0 1  6 7 4 5 //After the below exchange we should have this...each two elements in each communicator will exchange to next two elements in that same communicator 




     if(new_id < 2){ 

      MPI_Send(&my_num, 1, MPI_INT, 2 + new_id, 0, NEW_COMM); 
      MPI_Recv(&my_received, 1, MPI_INT, 2 + new_id, 0, NEW_COMM, MPI_STATUS_IGNORE);   

     } 
     else 
     { 
      MPI_Recv(&my_received, 1, MPI_INT, new_id - 2, 0, NEW_COMM, MPI_STATUS_IGNORE);   
      MPI_Send(&my_num, 1, MPI_INT, new_id - 2 , 0, NEW_COMM); 


     } 



    printf("old_id= %d received num= %d\n", old_id, my_received); 


    MPI_Finalize(); 

} 

回答

0

我編輯了自己的問題,使之更加清晰。另外,我還修復了與MPI_Comm_split調用創建的兩個新通信器相關的id。

第一個問題。調用MPI_Comm_split後的單個進程最多可以獲得一個新創建的通信器的句柄(對於通過MPI_UNDEFINED作爲顏色參數值的進程,返回的通信器最多可能等於MPI_COMM_NULL)。這就是爲什麼初學者通常不理解此調用的語義的原因:MPI_Comm_split是一個集體調用,因此它必須由原始通信器中的所有進程調用。因此,每個進程都調用一次,但函數返回$ k $ communicators,具體取決於所有進程提供的顏色參數的值,將進程劃分爲$ k $組。如果您對這種強大的機制感到不舒服,並且只想創建一個通信器,只需將MPI_UNDEFINED作爲由不能屬於新創建的通信器的進程進行的每次調用中的顏色參數的值提供即可。但是,你應該使用其他可用的函數來創建一個通信器,而不是MPI_Comm_split。

第二個問題。如果現在語義清晰,那麼您將立即認識到使用MPI_Comm_split返回的用於點對點或集體通信的通信器的進程永遠不會與作爲MPI_Comm_split返回的另一個通信器的一部分的進程交換數據。傳播者提供了一個不同的傳播者世界,因爲每個傳播者已經關聯了一組不同的進程。

現在,即使被屬於even ids communicator的進程調用,您的代碼片段也不起作用。爲什麼?因爲當new_id < 2將從新的通信器中的等級0的進程正確地發送到新的通信器中的等級2的過程時執行的代碼,並且新的通信器中等級0的過程將從等級2的過程接收新的傳播者。 但是,其他分支是有缺陷的。事實上,在新的溝通者中,所有等級大於等於2的進程都將執行它,而不僅僅是等級爲2的進程。在這種情況下,這個分支將由新的偶數等級2,4和6的進程執行ids傳播者。當然,等級4和等級6的進程將永遠掛起,分別阻塞進程2和4從未發送的消息。

最後,由於相同的代碼也會由另一個新的奇數進程執行創建通信器,等級爲1的進程將嘗試從進程3發送和接收,而在其他分支中,等級爲3,5和7的進程將嘗試發送和接收。在這種情況下,進程5和7將永久掛起,分別阻塞進程3和5從未發送的消息。

的代碼很容易固定,如果你想與等級0和2。使用時只需將明確IDS 0和2改寫交換進程間的數據,如果如下:

if(!new_id){ 
    MPI_Send(&my_num, 1, MPI_INT, 2, 0, NEW_COMM); 
    MPI_Recv(&my_received, 1, MPI_INT, 2 + new_id, 0, NEW_COMM, MPI_STATUS_IGNORE); 
} 

if(new_id == 2){ 

    MPI_Recv(&my_received, 1, MPI_INT, 0, 0, NEW_COMM, MPI_STATUS_IGNORE);   
    MPI_Send(&my_num, 1, MPI_INT, 0, 0, NEW_COMM); 

} 
+0

謝謝!當我打印舊ID和新ID時,其打印old_id = 0新ID = 0 old_id = 1新ID = 0 old_id = 2新ID = 1 old_id = 3新ID = 1 old_id = 4新ID = 2 old_id = 5 new id = 2 old_id = 6 new id = 3 old_id = 7 new id = 3 而不是您編輯的那個。所以,這裏有兩個進程具有相同的id,例如id 0。在這種情況下,我如何區分進程,當我做mpi_send時,我需要接收者的id。在這種情況下,mpi_comm_split中的關鍵參數是否必須對區分進程做任何事情? – user3256520

+0

一如既往,您可以根據自己想要使用的溝通器中的排名區分流程。關鍵參數允許您向MPI表明您不關心排序重新排序,允許MPI自由選擇新的排序(通過在關鍵參數的所有進程中傳遞相同的值完成),或者明確地通過一個不同的排序根據您自己的排名順序爲關鍵參數賦值。因此,如果你正確調用MPI_Comm_split,你會得到兩個新的通信器,但有兩種可能性。 –

+0

1)第一次通過等級0,2,4,6第二通信等級1,3,5,7和2)第一通信等級0,1,2,3第二通信等級0,1,2,3 。在第二種情況下,您必須簡單地在發送/接收數據時採取相應措施。例如,在第一種情況下,排名爲0和2的進程之間的交換成爲第二種情況,而在排名爲0和1的進程之間進行交換。爲了確保您使用的是正確的過程,只需檢查如下:if(!old_id &&!new_id)for proc在舊的通訊服務中的排名爲0 –

相關問題