內容概要
- Fonctions 功能
- Communications bloquantes 阻塞式溝通
- Envoi bloquant, mode bufferisé •阻塞發送,緩存模式
- Envoi bloquant, mode synchrone •阻塞發送,同步模式
- Envoi bloquant, mode ready •阻塞發送,准備模式
- Envoi bloquant, mode standard •阻塞發送,標准模式
- Communications non bloquantes •非阻塞溝通模式
O- 功能
⚠️ 此圖很重要,注意搭配使用! MPI_Recv 對應左邊那一列,MPI_Irecv對應右邊那一列
標准發送使用的模式由MPI在每個調用時決定。
MPI_Send,MPI_Bsend,MPI_Ssend,MPI_Rsend函數都具有相同的原型
MPI_Isend,MPI_Ibsend,MPI_Issend,MPI_Irsend函數都具有相同的原型
一、阻塞通信
當通訊存儲空間(數據+信封)可以在釋放后立即告訴下一個,而立即被重新使用時,這稱為阻塞溝通。
就是說::::通信不會被阻塞,阻塞的是內存!!!!!
(用完以后及時告訴其他人“我用完了,你們快來用吧”)
??????
對於“重用”,意思是:
對於發送者,可以修改要發送的數據上的指針,並且可以釋放指針本身而不影響通信(通常,MPI功能復制要傳送的數據在臨時緩存中),
對於接收器,指向要接收的數據的指針包含所有傳輸的數據,並且可以讀取元素。
對發送者的阻塞(不幸是標准)感到困惑的地方:
該術語適用於包含要傳輸的數據的內存空間,而不適用於通信。
該術語並不意味着發件人等待通話結束才能退出MPI功能。
在數據傳輸開始之前,發送者甚至可以退出MPI功能。
接收這沒有混淆:
當對阻塞接收的MPI功能的呼叫終止時,通信被有效終止
1. 阻塞-緩存模式 mode bufferisé
以緩存模式發送時,信息和信封將被復制到發送過程的存儲器中的其他位置。
相關函數:MPI_Bsend。
即使接收過程尚未處於等待消息的狀態(它尚未到達接收方),也可以調用MPI_Bsend。
即使接受者尚未收到整個消息,或者尚未准備開始接收消息,對MPI_Bsend的調用也可終止。
如果在調用MPI_Bsend發送時 接收者正在等待別的消息,則可以省略該buffer的消息(原來有別的在忙,先忽略這個消息,忙完別的再說)。
小結:因為此模式下,消息是存在緩存區的,不會直接到達接受者,不會要求接受者馬上接收,所以接受者和發送者互不干擾。什么時候啟用和停止MPI_Ssend都無所謂。
2. 阻塞發送-同步模式 mode synchrone
在同步模式下發送時,發送過程必須等待接收功能完成。
相關函數:MPI_Ssend。
即使接收過程尚未等待消息(尚未到達接收功能),也可以完成對MPI_Ssend的調用。(接受者沒准備好,發送者也可以發MPI_Ssend)
這是同步兩個進程的好方法。
在非阻塞接收的情況下(並且僅在這種情況下),接收功能以及對MPI_Ssend的調用可以在沒有完全傳送消息的情況下結束。(接收中斷)
小結:此模式下,接受者沒准備,發送者也能發送,但是發送者要等到接受者完全接受之后發送過程才能停止。
3. 阻塞發送-准備模式 mode ready
准備發送 僅在接收者已准備/等待 接收消息時才是正確的。
相關函數:MPI_Rsend。
可以省略某些通信操作,但是需要提前安排調度
接收過程不等待消息時 采用的行為是未確定的。
很少使用,因為非常危險。
4. 阻塞發送-標准模式 mode standard (根據情況選擇)
標准模式的確切行為是在發送時決定的。
相關函數:MPI_Send。
根據數據的大小/進程的進度,MPI_Send將以MPI_Bsend,MPI_Ssend或MPI_Rsend的形式運行。
事先不可能確定他的行為。
二、 非阻塞通信
非阻塞調用 開始發送或接收消息后立即終止(程序繼續執行)。
允許您在通訊過程中繼續計算。
任何非阻塞呼叫都需要調用MPI_Wait函數(或其他同類函數)來正確完成調用。
在非阻塞發送的情況下,在調用MPI_Wait之前,包含該消息的內存不能被重用(但可以被讀取)。
在非阻塞接收的情況下,在調用MPI_Wait之前,不能讀取用於接收消息的內存。
非阻塞發送可以與阻塞接收配對,反之亦然
int MPI_Isend(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request); int MPI_Irecv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Request *request); int MPI_Wait(MPI_Request *request, MPI_Status *status);
// non-bloquant.c #include <mpi.h> #include <stdio.h> int main(int argc, char** argv) { MPI_Init(NULL, NULL); int wrank; MPI_Comm_rank(MPI_COMM_WORLD, &wrank); int witness = 0; MPI_Request request; if (wrank==2) { int modifier = 1; MPI_Isend(&modifier, 1, MPI_INT, 3, 28, MPI_COMM_WORLD, &request); // Computations. MPI_Wait(&request, MPI_STATUS_IGNORE); } else if (wrank==3) { MPI_Irecv(&witness, 1, MPI_INT, 2, 28, MPI_COMM_WORLD, &request); // Other computations. MPI_Wait(&request, MPI_STATUS_IGNORE); } printf("Rang %d, witness %d.\n", wrank, witness); MPI_Finalize(); return 0; }
$ mpirun -n 4 source
Rang 0, witness 0. //無關進程
Rang 2, witness 0. //發送者
Rang 3, witness 1. //接受者
Rang 1, witness 0. //無關進程
⚠️:每個非阻塞調用都需要一個MPI_Wait, request是非阻塞呼叫的身份標識