2015-08-18 36 views
1

我知道MPI_SENDRECV可以解決死鎖問題(當我們使用經典的MPI_SENDMPI_RECV函數時)。MPI - 具有異步功能的MPI_SENDRCV的等效

我想知道,如果MPI_SENDRECV(sent_to_process_1, receive_from_process_0)等同於:

MPI_ISEND(sent_to_process_1, request1) 
MPI_IRECV(receive_from_process_0, request2) 
MPI_WAIT(request1) 
MPI_WAIT(request2) 

異步MPI_ISENDMPI_RECV功能?

從我所看到的,MPI_ISENDMPI_RECV創建了一個fork(即2個進程)。所以如果我遵循這個邏輯,MPI_ISEND的第一個調用會生成2個進程。其中一個進行通信,另一個呼叫MPI_RECV,其自身分出2個進程。

但是一旦第一個MPI_ISEND的通信完成後,第二個過程再次調用MPI_IRECV?有了這個邏輯,上述的等效似乎並沒有有效...

也許我應該改成這樣:

MPI_ISEND(sent_to_process_1, request1) 
MPI_WAIT(request1) 
MPI_IRECV(receive_from_process_0, request2) 
MPI_WAIT(request2) 

但我認爲,它可以同時創建死鎖。

任何人都可以給我另一種解決方案,使用MPI_ISEND,MPI_IRECVMPI_WAIT獲得相同的行爲MPI_SEND_RECV

回答

-1

我通常如何做到這一點的節點i與節點通信的I + 1:

mpi_isend(send_to_process_iPlus1, requests(1)) 
mpi_irecv(recv_from_process_iPlus1, requests(2)) 
... 
mpi_waitall(2, requests) 

你可以看到如何訂購你的命令,這種方式與非阻塞通信允許你(在...上面)在通信過程中執行任何不依賴於發送/接收緩衝區的計算。使用通信重疊計算對於最大化性能通常至關重要。

mpi_send_recv另一方面(同時避免任何死鎖問題)仍然是阻塞操作。因此,在整個發送/接收過程中,程序必須保持在該例程中。

最終要點:您可以初始化2個以上的請求,並使用上述結構以相同的方式等待所有請求,處理2個請求。例如,開始與節點i-1的通信也很容易,並等待全部4個請求。使用mpi_send_recv你必須始終有一個配對的發送和接收;如果你只想發送?

+0

好的,謝謝。我認爲第一個MPI_ISEND之後有兩個進程,一個處理通信(發送到上面例子中的進程1),另一個傳遞給MPI_IRECV函數。這樣,我認爲MPI_IRECV應該被調用兩次(在fork之後和第一次調用完成時)。在我的例子中,MPI_WAIT只是阻塞,直到request_1完成爲止:我們不能說每個MPI_ISEND和MPI_IRECV都執行fork(創建2個進程,如POSIX pthread的觀點),是嗎? MPI_WAIT的底層實現是什麼(它是POSIX「pthread_join」?)? – youpilat13

+0

因爲您已經在使用MPI流程(或排名)分解問題,所以稱它們爲流程是不好的。然而,如果你真的想這樣想,那麼是的,有一個分叉,其中1個「進程」處理通信,1個「進程」在代碼中繼續。請注意,只要通信結束,通信「進程」就會死亡。所以你的'waitall'只適用於每個MPI進程 - 而不是從fork創建的每個「進程」。 – NoseKnowsAll

+0

至於'mpi_wait'的底層實現,它依賴於你正在使用的MPI實現。 MPI標準並沒有規定如何實現功能,而只是MPI兼容實現的結果。最後,pthread和MPI是兩種不同的思想流派,所以我不會對它們進行比較。這就像試圖比較OpenMP和MPI一樣......它們只是創建並行代碼的根本不同的方法。 – NoseKnowsAll

0

在問題和其他答案中存在一些危險的思路。當您啓動非阻塞MPI操作時,MPI庫不會創建新的進程/線程/等。您正在考慮更像OpenMP的並行區域,我相信,創建新線程/任務以完成某些工作。

在MPI中,開始一個非阻塞操作就像告訴MPI庫,當MPI有機會完成這些操作時,你有一些事情想完成。有很多同樣有效的選擇時,他們實際上是完成了:

  1. 這可能是因爲,當你調用一個阻塞完成功能(如MPI_WAITMPI_WAITALL),他們都得到稍後再進行。這些函數可以確保在完成阻塞完成調用後,所有作爲參數傳入的請求都已完成(在您的情況下,爲MPI_ISENDMPI_IRECV)。無論實際操作何時發生(請參閱下面的幾個項目符號),作爲應用程序,您都不能認爲它們已完成,直到它們被MPI_WAITMPI_TEST之類的函數實際標記爲已完成爲止。
  2. 這些操作可能會在另一個MPI操作期間「在後臺」完成。舉例來說,如果你做類似下面的代碼:

    MPI_Isend(..., MPI_COMM_WORLD, &req[0]); 
    MPI_Irecv(..., MPI_COMM_WORLD, &req[1]); 
    MPI_Barrier(MPI_COMM_WORLD); 
    MPI_Waitall(2, req); 
    

    MPI_ISENDMPI_BARRIERMPI_IRECV可能會實際上做後臺的數據傳輸。這是因爲作爲一個應用程序,您在調用MPI_BARRIER期間將應用程序的「控制權」轉移到MPI庫。這使得圖書館可以在任何正在進行的MPI操作上取得進展。最有可能的情況是,當MPI_BARRIER完成時,其他大多數事情都是先完成的。

  3. 某些MPI庫允許您指定想要「進度線程」。這告訴MPI庫在後臺啓動另一個線程(不是線程!=進程),在您的應用程序在主線程中繼續執行時,它將爲您實際執行MPI操作。

請記住,所有的這些到底需要你實際調用MPI_WAITMPI_TEST或其他一些功能像它,以確保您的操作實際上是完整的,但沒有這些產生新的線程或進程做爲你調用你的非阻塞函數。那些實際上就像你將它們粘在要做的事情列表上一樣(實際上,大多數MPI庫是如何實現它們的)。

MPI_SENDRECV是如何實現的,最好的辦法是做一個完成函數的兩個非阻塞調用:

MPI_Isend(..., MPI_COMM_WORLD, &req[0]); 
MPI_Irecv(..., MPI_COMM_WORLD, &req[1]); 
MPI_Waitall(2, req); 
相關問題