2012-05-07 45 views
3

我是MPI的新手。我有4個進程:進程1到3填充一個向量並將其發送到進程0,進程0將向量收集到一個很長的向量中。我的代碼可以工作(發佈時間太長),但進程0的recv操作笨拙而且非常緩慢。MPI按根進程收集數組

在抽象中,代碼執行以下操作:

MPI::Init(); 
int id = MPI::COMM_WORLD.Get_rank(); 

if(id>0) { 
    double* my_array = new double[n*m]; //n,m are int 
    Populate(my_array, id); 
    MPI::COMM_WORLD.Send(my_array,n*m,MPI::DOUBLE,0,50); 
} 

if(id==0) { 
    double* all_arrays = new double[3*n*m]; 
    /* Slow Code Starts Here */ 
    double startcomm = MPI::Wtime(); 
    for (int i=1; i<=3; i++) { 
    MPI::COMM_WORLD.Recv(&all_arrays[(i-1)*m*n],n*m,MPI::DOUBLE,i,50); 
    } 
    double endcomm = MPI::Wtime(); 
    //Process 0 has more operations... 
} 
MPI::Finalize(); 

事實證明,endcomm - startcomm佔的總時間的50%(0.7秒相比1.5秒的程序來完成)。

有沒有更好的方式從進程1-3接收向量並將它們存儲在進程0的all_arrays

我檢出了MPI :: Comm :: Gather,但我不確定如何使用它。特別是,它是否允許我指定進程1的數組是all_arrays中的第一個數組,第二個進程2的數組等等?謝謝。

編輯:我刪除了「慢」的循環,而是放之間以下的「如果」塊:

MPI_Gather(my_array,n*m,MPI_DOUBLE, 
    &all_arrays[(id-1)*m*n],n*m,MPI_DOUBLE,0,MPI_COMM_WORLD); 

同樣的性能下降造成的。這是否與這樣一個事實有關:在嘗試下一個個體之前,根過程「等待」每個個體接收完成?或者,這不是正確的思考方式嗎?

+0

只是一個簡單的評論 - C++綁定在當前的MPI標準版本2.2中被棄用,並且在即將到來的MPI 3.0中將被完全刪除。爲了便於攜帶,建議您學習並使用C接口。 –

+0

程序中有多少'n'和'm',以及您的機器之間有什麼樣的連接? – suszterpatt

+0

Hristo,謝謝 - 我將我的代碼更改爲C接口。 – covstat

回答

5

是的,MPI_Gather將做到這一點。從ANL頁MPI_Gather

int MPI_Gather(void *sendbuf, int sendcnt, MPI_Datatype sendtype, 
       void *recvbuf, int recvcnt, MPI_Datatype recvtype, 
       int root, MPI_Comm comm) 

這裏,sendbuf,你對每個進程(my_array)陣列。 recvbuf是在收集短陣列的接收過程中的長陣列(all_arrays)。接收過程中的短陣列正被複制到長陣列中的連續位置,所以您不必擔心自己做這件事。來自每個進程的數組將被連續排列在長陣列中。

編輯:

在接收過程中不收集有助於sendbuf的情況下,你可能想使用MPI_Gatherv,而不是(感謝@HristoIliev指出這一點)。

+3

由於0級不會發送給自己,所以使用'MPI_Gatherv()'會更好。 –

+0

IRO-bot,謝謝。請參閱上面關於使用MPI_Gather的編輯。 – covstat

+0

@HristoIliev謝謝你,先生,這是正確的! – milancurcic