- 如何編寫並行程序?
- 任務並行:將待解決問題所需要執行的各個任務分配到各個核上執行
- 數據並行:將待解決的問題所需要處理的數據分配給各個核,每個核在分配到的數據集上執行大致相似的操作。
- 協調過程
- 通信
- 負載平衡:每個核被分配到大致相同數目的數據來計算
- 同步
- 並行系統的種類
- 共享內存系統:各個核能夠共享訪問計算機的內存,理論上每個核能夠讀、寫內存的所有區域。-----Pthreads、OpenMP
- 分布式內存系統:每個核擁有自己的私有內存,核之間的通信是顯式的,需要使用類似於網絡中發送消息的機制。-----MPI
- 並發計算、分布式計算
- 並發計算:一個程序的多個任務在同一時段內可以同時執行
- 並行計算:一個程序通過多個任務緊密協作來解決某個問題
- 分布式計算:一個程序需要與其他程序協作來解決某個問題
因此,並行程序和分布式程序都是並發的
- MPI(消息傳遞接口)
MPI是可以被C,C++和Fortran程序調用的函數庫
第一個Hello World程序
設置一個進程負責輸出,其他進程向他發送要打印的消息
編譯:$ mpicc -g -Wall -o mpi_hello mpi_hello.c
- -g:允許使用調試器
- -Wall 顯示警告
- -o<outfile> 編譯出的可執行文件名為outfile
#include<stdio.h> #include<string.h> #include<mpi.h> const int MAX_STRING = 100 int main(void){ char greeting[MAX_STRING]; int comm_sz; /*number of process*/ int my_rank; /*my process rank*/ MPI_Init(NULL,NULL);/*初始化*/ MPI_Comm_size(MPI_COMM_WORLD, &comm_sz);/*獲取通信子的進程數,存放在comm_sz中*/ MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);/*獲取正在調用進程在通信子中的進程號*/ if(my_rank != 0){/*非0號進程 向0號進程發送消息*/ sprintf(greeting, "Greetings from process %d of %d! ",my_rank, comm_sz); MPI_Send(greeting, strlen(greeting)+1, MPI_CHAR, 0, 0,MPI_COMM_WORLD); }else{/*0號進程 負責接收其他進程發過來的消息,並打印出來*/ printf("Greetings from process %d of %d! \n",my_rank,comm_sz); for( int q = 1; q < comm_sz; q++){ MPI_Recv(greeting, MAX_STRING, MPI_CHAR, q, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); printf("%s\n", greeting); } } MPI_Finalize();/*結束*/ return 0; }
1.首先要包含C語言頭文件stdio.h和string.h ,加上一個mpi.h頭文件
2.命名:MPI定義的標識符都由字符串MPI_開始。
下划線后的第一個字母大寫,表示函數名和MPI定義的類型
MPI定義的宏和常量的所有字母都大寫,這樣可以區分什么是MPI定義的什么是用戶程序定義的
- MPI_Init和MPI_Finalize
- MPI_Comm_size和MPI_Comm_rank
MPI_Comm_size函數在第二個參數處返回通信子的進程數
MPI_Comm_rank函數返回正在調用進程在通信子中的進程號
- MPI_Send
消息組裝完畢后,發送進程可以緩沖消息或阻塞消息
- 緩沖:消息將會被放在內存中
- 阻塞:系統將會阻塞,一直等待
實現方法:如果一條消息的大小小於“截止”大小,它將會被緩沖;如果大於截止大小,那么將會被阻塞
int MPI_Send( void* msg_buf_p,/*in*/ int msg_size,/*in*/ MPI_Datatype msg_type, /*--消息的內容*/ int dest, int tag, MPI_Comm communicator/*消息的目的地*/ );
- MPI_Recv
總是阻塞的,直到等待到一條匹配的消息。
int MPI_Recv( void* msg_buf_p,/*out*/ int buf_size, MPI_Datatype buf_type, int source, int tag, MPI_Comm communicator, MPI_Status* status_p /*out*/ );
- 消息匹配問題
如果0號進程只是簡單的按照進程號順序的接收結果,即先接收1號進程的結果,在接收2號進程的結果,以此類推,但如果comm_sz-1號進程是第一個完成工作的,那么有可能comm_sz-1號進程必須等待其他進程的完成。
為避免這個問題,MPI提供了一個特殊的常量MPI_ANY_SOURCE,可以傳遞給MPI_Recv了。如果0號進程執行下列代碼,那么他可以按照進程完成工作的順序來接收結果了
for (i = 1; i < comm_sz;i++){ MPI_Recv(result, result_sz, result_type, MPI_ANY_SOURCE, result_tag, comm, MPI_STATUS_IGNORE); Process_result(result); }
- status_p參數
接收者通過檢查一下兩個成員來確定發送者和標簽:
status.MPI_SOURCE
status.MPI_TAG
- MPI_Get_count函數
MPI_Get_count(&status, recv_type, &count)
int MPI_Get_count( MPI_Status* status_p, MPI_Datatype type, int* count_p )
注:count值不能簡單的作為MPI_Status變量的成員直接訪問
- MPI消息的不可超越性
- 同一進程發送兩條消息給進程t:第一條消息必須在第二條消息之前可用
- 不同進程發送消息給進程t:信息達到順序沒有限制