- 如何編寫並行程序?
- 任務並行:將待解決問題所需要執行的各個任務分配到各個核上執行
- 數據並行:將待解決的問題所需要處理的數據分配給各個核,每個核在分配到的數據集上執行大致相似的操作。
- 協調過程
- 通信
- 負載平衡:每個核被分配到大致相同數目的數據來計算
- 同步
- 並行系統的種類
- 共享內存系統:各個核能夠共享訪問計算機的內存,理論上每個核能夠讀、寫內存的所有區域。-----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:信息達到順序沒有限制
