MPI聚合函式
阿新 • • 發佈:2020-07-25
MPI聚合通訊
- MPI_Barrier
int MPI_Barrier(
MPI_Comm comm
);
所有在該通道的函式都執行完後,才開始其他步驟。
0程序在狀態T1呼叫MPI_Barrier
函式,並在該位置掛起,等待其他程序到達。最後在T4狀態同時進行。
例子:
#include<stdio.h> #include<mpi.h> #include<stdlib.h> #include<time.h> int main(int argc, char* argv[]) { int rank, nprocs; MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD, &nprocs); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Barrier(MPI_COMM_WORLD); printf("Hello,world,I am %d of %d\n", rank, nprocs); MPI_Finalize(); return 0; }
- MPI_Bcast
int MPI_Bcast(
void *buffer,
int count,
MPI_Datatype datatype,
int root,
MPI_Comm comm
);
廣播函式,root表示要廣播的程序。傳送和接收程序都需要寫該函式。
例子:
#include<stdio.h> #include<mpi.h> #include<stdlib.h> #include<time.h> int main(int argc, char* argv[]) { int rank,nproc; int ibuf; MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD, &nproc); MPI_Comm_rank(MPI_COMM_WORLD, &rank); if (rank == 0) ibuf = 8888; else ibuf = 0; MPI_Bcast(&ibuf, 1, MPI_INT, 0, MPI_COMM_WORLD); if (rank != 0) { printf("rank = %d ibuf = %d\n", rank, ibuf); } MPI_Finalize(); return 0; }
- MPI_Gather
int MPI_Gather(
void *sendbuf,
int sendcnt,
MPI_Datatype sendtype,
void *recvbuf,
int recvcnt,
MPI_Datatype recvtype,
int root,
MPI_Comm comm
);
每個程序(包括root程序)都要傳送buffer給root程序,root程序接收到這些buffer並且按照順序排好序。
例子:
#include<stdio.h> #include<mpi.h> #include<stdlib.h> #include<time.h> int main(int argc, char* argv[]) { int rank, nproc; int isend, irecv[32]; MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD, &nproc); MPI_Comm_rank(MPI_COMM_WORLD, &rank); isend = rank + 1; MPI_Gather(&isend, 1, MPI_INT, irecv, 1, MPI_INT, 0, MPI_COMM_WORLD); if (rank == 0) { for (int i = 0; i < nproc; i++) { printf("%d \n", irecv[i]); } } MPI_Finalize(); return 0; }
- MPI_Gatherv
int MPI_Gatherv(
void *sendbuf,
int sendcnt,
MPI_Datatype sendtype,
void *recvbuf,
int *recvcnts,
int *displs,// 接收的資料放在說明位置,即位移。
MPI_Datatype recvtype,
int root,
MPI_Comm comm
);
是MPI_Gather函式的一個擴充套件,recvcnts是陣列,允許每個程序的數量不同,而且每個程序的位置更靈活。
例子:
#include<stdio.h>
#include<mpi.h>
#include<stdlib.h>
#include<time.h>
int main(int argc, char* argv[])
{
//這裡為了簡單,假設有4個程序。
int send_buffer[6];
int recv_buffer[6];
int rank, nproc;
int receive_counts[4] = { 0,1,2,3 };
int receive_disp[4] = { 0,0,1,3 };//偏移陣列
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &nproc);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
//初始化資料
for (int i = 0; i < rank; i++)
{
send_buffer[i] = rank;
recv_buffer[i] = rank+1;
}
MPI_Gatherv(send_buffer, rank, MPI_INT, recv_buffer, receive_counts, receive_disp, MPI_INT, 0, MPI_COMM_WORLD);
if (rank == 0)
{
for (int i = 0; i < 6; i++)
{
printf("[%d]", recv_buffer[i]);
}
}
MPI_Finalize();
return 0;
}
- MPI_Scatter
int MPI_Scatter(
void *sendbuf,
int sendcnt,
MPI_Datatype sendtype,
void *recvbuf,
int recvcnt,
MPI_Datatype recvtype,
int root,
MPI_Comm comm
);
MPI_Scatter與MPI_Bcast非常相似,都是一對多的通訊方式,不同的是後者的0號程序將相同的資訊傳送給所有的程序,而前者則是將一段array 的不同部分發送給所有的程序。
例子:
#include<stdio.h>
#include<mpi.h>
#include<stdlib.h>
#include<time.h>
#define MAX_PRO 10//最大程序數
int main(int argc, char* argv[])
{
int rank, nproc;
int table[MAX_PRO][MAX_PRO];
int row[MAX_PRO];
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &nproc);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
if (rank == 0)
{
for (int i = 0; i < nproc; i++)
{
for (int j = 0; j < MAX_PRO; j++)
{
table[i][j] = i + j;
}
}
}
MPI_Scatter(&table[0][0], MAX_PRO, MPI_INT, &row[0], MAX_PRO, MPI_INT, 0, MPI_COMM_WORLD);
if (rank != 0)
{
for (int i = 0; i < MAX_PRO; i++)
{
printf("%d ", row[i]);
}
printf("processs of %d\n",rank);
}
MPI_Finalize();
return 0;
}
- MPI_Alltoall
int MPI_Alltoall(
void *sendbuf,
int sendcount,
MPI_Datatype sendtype,
void *recvbuf,
int recvcount,
MPI_Datatype recvtype,
MPI_Comm comm
);
當前程序向其他每個程序(包括自己)要傳送資料,都是傳送sendbuf中的資料。接收到不同程序的資料。
例子:
#include<stdio.h>
#include<mpi.h>
#include<stdlib.h>
#include<time.h>
int main(int argc, char* argv[])
{
int rank, nproc;
int send[1];
int recv[10];
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &nproc);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
send[0] = rank*rank;
for (int i = 0; i < 10; i++)
{
recv[i] = 0;
}
MPI_Alltoall(&send, 1, MPI_INT, recv, 1, MPI_INT, MPI_COMM_WORLD);
if (rank == 0)
{
for (int i = 0; i < 10; i++)
{
printf("%d ", recv[i]);
}
}
MPI_Finalize();
return 0;
}
MPI歸約操作
- MPI_Reduce
int MPI_Reduce(
void *sendbuf,
void *recvbuf,
int count,
MPI_Datatype datatype,
MPI_Op op,
int root,
MPI_Comm comm
);
MPI_Op有如下型別:
運算操作符 | 描述 | 運算操作符 | 描述 |
---|---|---|---|
MPI_MAX | 最大值 | MPI_LOR | 邏輯或 |
MPI_MIN | 最小值 | MPI_BOR | 位與 |
MPI_SUM | 求和 | MPI_LXOR | 邏輯異或 |
MPI_PROD | 求積 | MPI_BXOP | 位異或 |
MPI_LAND | 邏輯與 | MPI_MINLOC | 計算一個全域性最小值 |
MPI_BAND | 位與 | MPI_MAXLOC | 計算一個全域性最大值 |
將通訊子內各程序的同一個變數參與規約計算,並向指定的程序輸出計算結果。
例子:
#include<stdio.h>
#include<mpi.h>
#include<stdlib.h>
#include<time.h>
int main(int argc, char* argv[])
{
int rank, nproc;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &nproc);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
int send = rank;
int recv;
MPI_Reduce(&send, &recv, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);
if (rank == 0)
{
printf("%d", recv);
}
MPI_Finalize();
return 0;
}
- MPI_Scan
int MPI_Scan(
void *sendbuf,
void *recvbuf,
int count,
MPI_Datatype datatype,
MPI_Op op,
MPI_Comm comm
);
字首和函式 MPI_Scan(),將通訊子內各程序的同一個變數參與字首規約計算,並將得到的結果傳送回每個程序,使用與函式 MPI_Reduce() 相同的操作型別。
例子:
#include<stdio.h>
#include<mpi.h>
#include<stdlib.h>
#include<time.h>
int main(int argc, char* argv[])
{
int rank, nproc;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &nproc);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
int send = rank;
int recv;
MPI_Scan(&send, &recv, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
printf("the %d process is %d", rank, recv);
MPI_Finalize();
return 0;
}
- MPI_Reduce_scatter
int MPI_Reduce_scatter(
void *sendbuf,
void *recvbuf,
int *recvcnts,
MPI_Datatype datatype,
MPI_Op op,
MPI_Comm comm
);
將規約結果分片傳送到各程序.
#include<stdio.h>
#include<mpi.h>
#include<stdlib.h>
#include<time.h>
int main(int argc, char** argv)
{
int* sendbuf, recvbuf, * recvcounts;
int size, rank;
MPI_Comm comm;
MPI_Init(&argc, &argv);
comm = MPI_COMM_WORLD;
MPI_Comm_size(comm, &size);
MPI_Comm_rank(comm, &rank);
sendbuf = (int*)malloc(size * sizeof(int));
for (int i = 0; i < size; i++)
sendbuf[i] = i;
recvcounts = (int*)malloc(size * sizeof(int));
for (int i = 0; i < size; i++)
recvcounts[i] = 1;
MPI_Reduce_scatter(sendbuf, &recvbuf, recvcounts, MPI_INT, MPI_SUM, comm);
printf("the %d process is %d", rank, recvbuf);
MPI_Finalize();
return 0;
}