MPI是一個跨語言的通訊協議,用於並發編程。MPI標准定義了一組具有可移植性的編程接口。
安裝環境
MPICH 是開源的消息傳遞接口(MPI)標准的實現。
下載地址
# 解壓文件
tar -xzvf mpich-3.2.1.tar.gz
cd mpich-3.2.1
# /usr/local/Cellar/mpich 改為你要安裝 MPICH 的路徑
./configure –-prefix=/usr/local/Cellar/mpich |& tee c.log
make |& tee m.log
make install |& tee mi.log
# 將你安裝 MPICH 的路徑添加到 PATH
export PATH=/usr/local/Cellar/mpich:$PATH;
編程例子
1. 簡單 MPI 編程之進程識別
#include <mpi.h> // mpi 頭文件
#include <stdio.h>
int main(int argc, char **argv) {
int numprocs, myid;
MPI_Init (&argc, &argv); // 初始化 MPI 執行環境
MPI_Comm_size (MPI_COMM_WORLD, &numprocs); // 獲取有多少個進程屬於 MPI_COMM_WORLD 通信域
MPI_Comm_rank (MPI_COMM_WORLD, &myid); // 獲取當前進程的 id
if (myid == 0) {
// 進程號為0的進程執行的操作...
} else {
// 其它進程執行的操作...
}
// 所有進程都執行的操作...
MPI_Finalize(); // 結束 MPI 執行環境
return 0;
}
2. MPI 簡單通信
#include <mpi.h> // mpi 頭文件
#include <stdio.h>
int main(int argc, char **argv) {
int data[100], myid;
MPI_Init (&argc, &argv);
MPI_Comm_rank (MPI_COMM_WORLD, &myid);
if (myid == 0)
MPI_Send(data, 100, MPI_INT, 1, 0, MPI_COMM_WORLD);
else if (myid == 1)
MPI_Recv(data, 100, MPI_INT, 0, 0, MPI_COMM_WORLD,
MPI_STATUS_IGNORE);
MPI_Finalize(); // 結束 MPI 執行環境
return 0;
}
其中,MPI_SEND(buf, count, datatype, dest, tag, comm)
是發送消息的 API,
buf
是消息緩存區。
count
是消息大小。
datatype
是數據類型。
dest
是目的進程在指定的進程域 comm
的進程號。
tag
是用戶定義的消息的類型。
MPI_RECV(buf, count, datatype, source, tag, comm, status)
是(阻塞)接收消息的 API。
source
是來源進程在指定的進程域 comm
或 MPI_ANY_SOURCE
的進程號。
tag
可以是 MPI_ANY_TAG
。
status
用來接收更多信息,可以用 MPI_STATUS_IGNORE
如果我們不需要更多信息。
編譯運行程序
封裝的編譯器:
- 對於 C 程序:
mpicc test.c -o test
- 對於 C++ 程序:
mpicxx test.cpp -o test
- 對於 Fortran 77 程序:
mpif77 test.f -o test
- 對於 Fortran 90 程序:
mpif90 test.f90 -o test
你也可以鏈接其它庫:mpicc test.c -o test -lm
運行:
啟動 16 個進程:mpiexec -n 16 ./test
如果-n 指定的進程數超過了系統的CPU(核)數,就會報錯如下:
There are not enough slots available in the system to satisfy the 16 slots
that were requested by the application:
./test
Either request fewer slots for your application, or make more slots available
for use.
進階一些:
// 非阻塞發送。非阻塞接收為 MPI_Irecv,具體說明可以用 man 命令查詢.
int MPI_Isend(const void *buf, int count, MPI_Datatype datatype, int dest, int tag,
MPI_Comm comm, MPI_Request *request)
// 檢測非阻塞通信是否完成。阻塞等待為 MPI_Wait,可以等待全部(MPI_Waitall)、等待一些(MPI_Waitsome,MPI_Waitany)
nt MPI_Test( MPI_Request *request, int *flag, MPI_Status *status );
// 數據歸約:通過計算收集到的多個數據得到一個數據。
int MPI_Reduce (void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm)