MPI知識點總結

MPI知識點總結

  • 點對點
    • 阻塞式通信
      • MPI_Send
      • MPI_Recv
    • 非阻塞式通信
      • MPI_ISend
      • MPI_IRecv
      • MPI_Wait
  • 同步聚合
    • 柵欄同步
      • MPI_Barrier
  • 通信聚合
    • 廣播
      • MPI_Bcast
    • 分散
      • MPI_Scatter
    • 收集
      • MPI_Gather
    • 全部收集
      • MPI_Allgather
  • 規約聚合
    • 規約操作
      • MPI_Reduce
      • MPI_Allreduce

 

幾個重要函數

MPI_Scatter

MPI_Scatter與MPI_Bcast非常相似,都是一對多的通信方式,不同的是後者的0號進程將相同的信息發送給所有的進程,而前者則是將一段array 的不同部分發送給所有的進程,其區別可以用下圖概括:

MPI_Scatter(
    void* send_data,//存儲在0號進程的數據,array
    int send_count,//具體需要給每個進程發送的數據的個數
    //如果send_count爲1,那麼每個進程接收1個數據;如果爲2,那麼每個進程接收2個數據
    MPI_Datatype send_datatype,//發送數據的類型
    void* recv_data,//接收緩存,緩存 recv_count個數據
    int recv_count,
    MPI_Datatype recv_datatype,
    int root,//root進程的編號
    MPI_Comm communicator)

 

MPI_Gather

MPI_Gather和MPI_scatter剛好相反,他的作用是從所有的進程中將每個進程的數據集中到根進程中,同樣根據進程的編號對array元素排序,如圖所示:

MPI_Gather(
    void* send_data,
    int send_count,
    MPI_Datatype send_datatype,
    void* recv_data,
    int recv_count,//注意該參數表示的是從單個進程接收的數據個數,不是總數
    MPI_Datatype recv_datatype,
    int root,
    MPI_Comm communicator)

 

MPI_Allgather

當數據分佈在所有的進程中時,MPI_Allgather將所有的數據聚合到每個進程中。

MPI_Allgather(
    void* send_data,
    int send_count,
    MPI_Datatype send_datatype,
    void* recv_data,
    int recv_count,
    MPI_Datatype recv_datatype,
    MPI_Comm communicator)

 

MPI_Allgatherv

/*
 * 收集所有任務的數據並將組合數據傳送到所有任務
 * int MPI_Allgatherv(const void * sendbuf,int sendcount,MPI_Datatype sendtype,
 *      void * recvbuf,const int * recvcounts,const int * displs,
 *      MPI_Datatype recvtype,MPI_Comm comm) 
 *
 * sendbuf:要發送內容的起始地址
 * sendcount:要發送的數量
 * sendtype:要發送數據的類型
 * recvbuf:接收數據要存放的單元的地址
 * recvcounts:這是一個整數數組,包含從每個進程要接收的數據量,比如{0, 1} 從0號進程接收0個,從1號進程接收1個 
 * displs:這是一個整數數組,包含存放從每個進程接收的數據相對於recvbuf的偏移地址
 * recvtype:要接收的數據類型
 * comm:通信集合
 */

MPI_Allagtherv解決MPI_Allagther要求每個進程處理任務量必須均等的問題,通過recvcounts數組指定每個進程接收任務的數量,通過displs數組指定每個進程發送的數據在接收緩衝區中的偏移量。

 

MPI_Alltoall

int MPI_Alltoall(const void *sendbuf,    //發送緩衝區的起始地址
                int sendcount,           //要發送的數量
                 MPI_Datatype sendtype,  //發送的數據類型
                void *recvbuf,           //接收緩衝區的起始位置
                int recvcount,           //要接收的數量
                MPI_Datatype recvtype,   //要接收的類型
                MPI_Comm comm)           //通信子

函數原理示意圖如下,分別演示了發送緩衝區數據量爲1和2時的發送和接收情況:

 

MPI_Alltoallv

有時候,我們當前進程往其他進程發送的數據不一樣,個數也不一樣,這個時候就需要用MPI_Alltoallv來解決。該函數用法類似於MPI_Allgather和MPI_Allgatherv的區別,即發送緩衝區的大小可以不相同(通過數組指定大小)。

int MPI_Alltoallv(const void *sendbuf,
                    const int *sendcounts,                                                            
                    const int *sdispls,
                     MPI_Datatype sendtype,
                    void *recvbuf,
                    const int *recvcounts,
                    const int *rdispls,
                    MPI_Datatype recvtype,
                    MPI_Comm comm)

相比MPI_Alltoall,這個方法有幾個參數不一樣:
int* sendcounts 和int *recvcounts。這兩個參數你可以把它當做兩個數組,數組中的元素代表往其他節點各發送(接收)多少數據。比如說,sendcounts[0]=3,sendcounts[1]=4,代表該節點要往0號節點發送3個sendtype的數據,往1號節點發送4個sendtype的數據。
多了兩個參數,int *sdispls和int *rdispls,這兩個可以看做是數組,數組中的每個元素代表了要發送(接收)的那塊數據相對於緩衝區起始位置的位移量。

 

MPI_Reduce

歸約聚合類似於收集,但對收集的數據執行某種歸約操作,例如計算總和,查找最大值或執行某些用戶定義的操作。

規約函數 MPI_Reduce(),將通信子內各進程的同一個變量參與規約計算,並向指定的進程輸出計算結果。

MPI_METHOD MPI_Reduce(
    _In_range_(!= , recvbuf) _In_opt_ const void* sendbuf,  // 指向輸入數據的指針
    _When_(root != MPI_PROC_NULL, _Out_opt_) void* recvbuf, // 指向輸出數據的指針,即計算結果存放的地方
    _In_range_(>= , 0) int count,                           // 數據尺寸,可以進行多個標量或多個向量的規約
    _In_ MPI_Datatype datatype,                             // 數據類型
    _In_ MPI_Op op,                                         // 規約操作類型
    _mpi_coll_rank_(root) int root,                         // 目標進程號,存放計算結果的進程
    _In_ MPI_Comm comm                                      // 通信子
);

demo:

{
    int size, rank, data, dataCollect;
    MPI_Init(NULL, NULL);
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);

    data = rank;// 參與計算的數據
    MPI_Reduce((void *)&data, (void *)&dataCollect, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);// 所有的進程都要調用,而不是隻在目標進程中調用

    MPI_Finalize();
}

 

MPI_Allreduce

規約並廣播函數 MPI_Allreduce(),在計算規約的基礎上,將計算結果分發到每一個進程中,相比於 MPI_Reduce(),只是少了一個 root 參數。除了簡單的先規約再廣播的方法,書中介紹了蝶形結構全局求和的方法。

少了一個root參數是因爲該函數將計算的結果廣播到每個進程中去,各個進程均更新數據。

_Pre_satisfies_(recvbuf != MPI_IN_PLACE) MPI_METHOD MPI_Allreduce(
    _In_range_(!= , recvbuf) _In_opt_ const void* sendbuf,
    _Out_opt_ void* recvbuf,
    _In_range_(>= , 0) int count,
    _In_ MPI_Datatype datatype,
    _In_ MPI_Op op,
    _In_ MPI_Comm comm
);

demo:

{
    int size, rank, data, dataCollect;
    MPI_Init(NULL, NULL);
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);

    data = rank;
    MPI_Reduce((void *)&data, (void *)&dataCollect, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);// 所有的進程都要調用

    MPI_Finalize();
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章