MPI 基礎內容
1. MPI基本函數
1.1 初始化
int MPI_Init(int *argc, char ** argv)
通過MPI_Init
進入MPI環境,並完成初始化工作。
1.2 結束
int MPI_Finalize(void)
從MPI環境中退出
1.3 獲取進程編號
int MPI_Comm_rank(MPI_Comm comm, int *rank)
獲取當前進程在指定通信域中的編號,其中MPI_Comm
代表一個通信域。一個通信域指的是一個進程組和對應的通信上下文,常用的常量MPI_COMM_World
是所有進程在的通信域。編號保存在變量rank中。
1.4 獲取進程數目
int MPI_Comm_size(MPI_Comm comm, int *size)
獲得當前通信域中的進程數目,數目保存在變量size中。
1.5 發送消息
int MPI_Send(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm)
參數buf指的是要發送內容的首地址,count指的是發送的元素數目。datatype指的是要發送的數據類型,C語言中的數據類型,會與MPI的數據類型綁定,比如int會在MPI中綁定為MPI_INT。MPI預定義的數據類型表如下(部分內容):
MPI(C語言綁定) | C語言中的數據類型 |
---|---|
MPI_BYTE | |
MPI_DOUBLE | double |
MPI_FLOAT | float |
MPI_INT | int |
MPI_UNSIGNED_CHAR | unsigned char |
MPI_CHAR | signed char |
消息信封指的是<源/目的地址(source/dest),消息標簽(tag),通信域(MPI_Comm)>,表示接收/發送消息的地址。其中source/dest指的是源/目的進程的進程號,即從函數MPI_Comm_rank
中獲得的rank值。
1.6 接收消息
int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status)
變量status指的是返回狀態。在C語言中,狀態變量至少是由三部分組成的數據結構類型,這三個部分分別是MPI_SOURCE,MPI_TAG和MPI_ERROR,還可以包含其他部分。傳遞MPI_Status
參數時,需用語句MPI_Status status;
生成一個MPI_Status
類型的變量,然后將地址傳入。
1.7 簡單示例
一個簡單的MPI示例如下
#include "mpi.h" /*MPI頭函數,提供了MPI函數和數據類型定義*/
int main( int argc, char** argv )
{
int rank, size, tag=1;
int senddata,recvdata;
MPI_Status status;
MPI_Init(&argc, &argv); /*MPI的初始化函數*/
MPI_Comm_rank(MPI_COMM_WORLD, &rank); /*該進程編號*/
MPI_Comm_size(MPI_COMM_WORLD, &size); /*總進程數目*/
if (rank==0){
senddata=9999;
MPI_Send( &senddata, 1, MPI_INT, 1, tag, MPI_COMM_WORLD); /*發送數據到進程1*/
}
if (rank==1)
MPI_Recv(&recvdata, 1, MPI_INT, 0, tag, MPI_COMM_WORLD, &status); /*從進程0接收數據*/
MPI_Finalize(); /*MPI的結束函數*/
return (0);
}
2. 通信方式
2.1 通信域
通信域(Communicator)包括進程組(Process Group)和通信上下文等內容,用於描述通信進程之間的關系。進程組是進程的有限有序集合,集合的數目稱為進程組的大小,在一個大小為n的進程組中,進程按照0,1,2,……,n-1進行排列。通信上下文不是顯示的對象,只是作為通信域的一部分出現,用於安全的區別不同的通信以免互相干擾。MPI_COMM_WORLD是所有進程的集合。
通信域分為組內通信域和組間通信域,分別用來實現MPI的組內通信(Intra-communication)和組間通信(Inter-communication)。
2.2 管理通信域
常見的用於管理通信域的函數如下
函數名 | 含義 |
---|---|
MPI_Comm_size | 獲取指定通信域中進程的個數 |
MPI_Comm_rank | 獲取當前進程在指定通信域中的編號 |
MPI_Comm_compare | 對給定的兩個通信域進行比較 |
MPI_Comm_dup | 復制一個已有的通信域生成一個新的通信域,兩者除通信上下文不同外,其它都一樣。 |
MPI_Comm_create | 根據給定的進程組創建一個新的通信域 |
MPI_Comm_split | 從一個指定通信域分裂出多個子通信域,每個子通信域中的進程都是原通信域中的進程。 |
MPI_Comm_free | 釋放一個通信域 |
一個在MPI中創建新通信域的例子
MPI_Comm MyWorld, SplitWorld;
int my_rank,group_size, Color, Key;
MPI_Init(&argc, &argv);
MPI_Comm_dup(MPI_COMM_WORLD,&MyWorld);
MPI_Comm_rank(MyWorld,&my_rank);
MPI_Comm_size(MyWorld,&group_size);
Color=my_rank%3;
Key=my_rank/3;
MPI_Comm_split(MyWorld,Color,Key,&SplitWorld);
解釋如下
-
MPI_Comm_dup
MPI_Comm_dup(MPI_COMM_WORLD, &MyWorld)
創建一個新通信域MyWorld,包含於原通信域MPI_COMM_WORLD中相同的進程,但是具有不同的上下文。
-
MPI_Comm_split
MPI_Comm_split(MyWorld, Color, Key, &SplitWorld)
在通信域MyWorld的基礎上,產生幾個分割的通信域。原通信域中MyWorld中的進程按照不同的Color值處在不同的通信域中,每個進程在不同分割通信域中的編號則有Key值標識。
Rank in MyWorld 0 1 2 3 4 5 6 7 8 9 Color 0 1 2 0 1 2 0 1 2 0 Key 0 0 0 1 1 1 2 2 2 3 Rank in SplitWorld(Color=0) 0 1 2 3 Rank in SplitWorld(Color=1) 0 1 2 Rank in SplitWorld(Color=2) 0 1 2
2.3 組間通信
組間通信域是一種特殊的通信域,該通信域包括兩個進程組。不同進程組的進程通過組間通信域進行通信。一般把調用進程所在的進程組稱為本地進程組,而把另外一個稱為遠程進程組。
函數名 | 含義 |
---|---|
MPI_Comm_test_inter | 判斷給定的通信域是否為組間通信域 |
MPI_Comm_remote_size | 獲取指定組間通信域中遠程進程組的大小 |
MPI_Comm_remote_group | 返回給定組間通信域的遠程進程組 |
MPI_Intercomm_creat | 根據給定的兩個組內通信域生成一個組間通信域。 |
MPI_Intercomm_merge | 將給定組間通信域包含的兩個進程組合並,形成一個新的組內通信域 |
2.4 消息狀態
MPI_Status
是用來存放接收消息的消息狀態,包括:
- 消息的原進程標識——MPI_SOURCE
- 消息標簽——MPI_TAG
- 錯誤狀態——MPI_ERROR
- 其他——包括數據項個數等。
假設多個客戶進程發送消息給服務進程請求服務,通過消息標簽來標識客戶進程,從而服務進程采取不同的服務,示例如下:
while (true){
MPI_Recv(received_request,100,MPI_BYTE,MPI_Any_source,MPI_Any_tag,comm,&Status);
switch (Status.MPI_Tag) {
case tag_0: perform service type0;
case tag_1: perform service type1;
case tag_2: perform service type2;
}
2.5 點對點通信模式
MPI支持四種通信模式,同步、緩沖、標准、就緒四種。
-
同步通信模式
只有等相應等接收過程已經啟動,發送過程才能正確返回。
因此,當同步發送返回時,表示發送緩沖區中的數據已經被系統緩沖區緩存,並且已經開始發送。
-
緩沖通信模式
緩沖通信模式的發送不管接收操作是否已經啟動都可以執行。
但是需要用戶程序事先申請一塊足夠大的緩沖區,通過MPI_Buffer_attch實現,通過MPI_Buffer_detach來回收申請的緩沖區。
-
標准通信模式
是否對發送的數據進行緩沖由MPI的實現來決定,而不是由用戶程序來控制。發送是可以同步或緩沖的,取決於具體實現。
-
就緒通信模式
發送操作只有在接收進程相應的接收操作已經開始才進行發送。
當發送操作啟動而相應的接收還沒有啟動,發送操作將出錯。就緒通信模式的特殊之處是接收操作必須先於發送操作啟動。
MPI同時有阻塞和非阻塞兩種通信機制,它們的主要區別是返回后資源的可用性。阻塞通信的返回條件如下:
- 通信操作已經完成,即消息已發送或接收
- 調用的緩沖區可用性,若是發送操作,則該緩沖區可以被其他操作更新;若是接收操作,該緩沖區的數據已經完整,可以被正確引用。
MPI的發送支持四種通信模式,與阻塞屬性一起產生了MPI的8種發送操作,但是對於接收,只有阻塞接收和非阻塞接收兩種。
2.6 群集通信
群集通信是一個進程組中的所有進程都參加的全局通信操作,一般實現三個功能:通信、聚集和同步。通信主要完成組內數據的傳輸,聚集功能在通信的基礎上對給定的數據完成一定的操作,同步功能實現組內所有進程在執行進度上的一致性。
群集通信按照通信方向的不同,可以分為一對多通信、多對一通信和多對多通信,常見的通信函數如下:
類型 | 函數名 | 含義 |
---|---|---|
通信 | MPI_Bcast | 一對多廣播同樣的消息 |
MPI_Gather | 多對一收集各個進程的消息 | |
MPI_Gatherv | MPI_Gather的一般化 | |
MPI_Allgather | 全局收集 | |
MPI_Allgatherv | MPI_Allgather的一般化 | |
MPI_Scatter | 一對多散播不同的消息 | |
MPI_Scatterv | MPI_Scatter的一般化 | |
MPI_Alltoall | 多對多全局交換消息 | |
MPI_Alltoallv | MPI_Alltoall的一般化 | |
聚集 | MPI_Reduce | 多對一歸約 |
MPI_Allreduce | MPI_Reduce的一般化 | |
MPI_Reduce_scatter | MPI_Reduce的一般化 | |
MPI_Scan | 掃描 | |
同步 | MPI_Barrier | 路障同步 |