並行計算學習之並行程序設計導論


  • 如何編寫並行程序?
  1. 任務並行:將待解決問題所需要執行的各個任務分配到各個核上執行
  2. 數據並行:將待解決的問題所需要處理的數據分配給各個核,每個核在分配到的數據集上執行大致相似的操作。
  • 協調過程
  1. 通信
  2. 負載平衡:每個核被分配到大致相同數目的數據來計算
  3. 同步
  • 並行系統的種類
  1. 共享內存系統:各個核能夠共享訪問計算機的內存,理論上每個核能夠讀、寫內存的所有區域。-----Pthreads、OpenMP
  2. 分布式內存系統:每個核擁有自己的私有內存,核之間的通信是顯式的,需要使用類似於網絡中發送消息的機制。-----MPI

                       

  • 並發計算、分布式計算
  1. 並發計算:一個程序的多個任務在同一時段內可以同時執行
  2. 並行計算:一個程序通過多個任務緊密協作來解決某個問題
  3. 分布式計算:一個程序需要與其他程序協作來解決某個問題

  因此,並行程序和分布式程序都是並發的

  • 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

           消息組裝完畢后,發送進程可以緩沖消息或阻塞消息

  1. 緩沖:消息將會被放在內存中
  2. 阻塞:系統將會阻塞,一直等待

實現方法:如果一條消息的大小小於“截止”大小,它將會被緩沖;如果大於截止大小,那么將會被阻塞

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消息的不可超越性
  1. 同一進程發送兩條消息給進程t:第一條消息必須在第二條消息之前可用
  2. 不同進程發送消息給進程t:信息達到順序沒有限制

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM