MPI (Message Passing Interface) 是一种广泛使用的标准协议,用于编写高性能并行应用程序。它允许程序员编写可以运行在多台计算机上或单个多核处理器上的程序。MPI 提供了一系列的函数来处理进程间的通信和同步问题。以下是几个经典的 MPI 编程入门案例:
-
Hello World
- 这是最基本的 MPI 程序,它的目的是让每个进程输出一条消息,显示进程编号。这个例子主要是为了测试 MPI 环境是否正确设置。
#include <mpi.h> #include <stdio.h> int main(int argc, char *argv[]) { int rank, size; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &size); printf("Hello World from process %d of %d\n", rank, size); MPI_Finalize(); return 0; }
-
点对点通信
- 在这个例子中,一个进程发送一条消息给另一个进程,后者接收并打印消息。这演示了基本的
MPI_Send
和MPI_Recv
函数的使用。
#include <mpi.h> #include <stdio.h> int main(int argc, char *argv[]) { int rank, size; int myid, recvdata, senddata = 1234; MPI_Status status; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &size); if (rank == 0) { myid = 0; MPI_Send(&senddata, 1, MPI_INT, 1, 0, MPI_COMM_WORLD); printf("Process %d sent data to process 1.\n", myid); } else if (rank == 1) { myid = 1; MPI_Recv(&recvdata, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &status); printf("Process %d received data (%d) from process 0.\n", myid, recvdata); } MPI_Finalize(); return 0; }
- 在这个例子中,一个进程发送一条消息给另一个进程,后者接收并打印消息。这演示了基本的
-
并行求和
- 这个例子展示了如何使用 MPI 来并行地计算一组数字的总和。每个进程负责计算一部分数值的总和,然后所有进程使用
MPI_Reduce
函数来合并这些部分总和。
#include <mpi.h> #include <stdio.h> int main(int argc, char *argv[]) { int rank, size; int my_sum, global_sum; int numbers[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &size); // 计算每个进程的子数组的总和 my_sum = 0; for (int i = rank; i < 10; i += size) { my_sum += numbers[i]; } // 使用 MPI_Reduce 合并所有进程的结果 MPI_Reduce(&my_sum, &global_sum, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD); // 只有根进程打印结果 if (rank == 0) { printf("Global sum: %d\n", global_sum); } MPI_Finalize(); return 0; }
- 这个例子展示了如何使用 MPI 来并行地计算一组数字的总和。每个进程负责计算一部分数值的总和,然后所有进程使用
-
广播
- 广播是一种单播多收的通信模式,其中一个进程(通常是根进程)向所有其他进程发送相同的消息。
#include <mpi.h> #include <stdio.h> int main(int argc, char *argv[]) { int rank, size; int message = 0; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &size); if (rank == 0) { message = 12345; } MPI_Bcast(&message, 1, MPI_INT, 0, MPI_COMM_WORLD); printf("Process %d received message: %d\n", rank, message); MPI_Finalize(); return 0; }
-
散列
- 散列是一种多播多收的通信模式,其中根进程将不同的数据分发给不同的进程。
#include <mpi.h> #include <stdio.h> int main(int argc, char *argv[]) { int rank, size; int my_data, root_data[size]; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &size); if (rank == 0) { for (int i = 0; i < size; i++) { root_data[i] = i + 1; } MPI_Scatter(root_data, 1, MPI_INT, &my_data, 1, MPI_INT, 0, MPI_COMM_WORLD); } else { MPI_Scatter(NULL, 1, MPI_INT, &my_data, 1, MPI_INT, 0, MPI_COMM_WORLD); } printf("Process %d received data: %d\n", rank, my_data); MPI_Finalize(); return 0; }
-
归约
- 归约是另一种集合通信操作,类似于并行求和,但可以执行多种运算,如最小值、最大值等。
#include <mpi.h> #include <stdio.h> int main(int argc, char *argv[]) { int rank, size; int value = 0, result; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &size); value = rank + 1; MPI_Reduce(&value, &result, 1, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD); if (rank == 0) { printf("Maximum value is: %d\n", result); } MPI_Finalize(); return 0; }
这些案例涵盖了 MPI 中的基本概念和技术,可以帮助新手快速上手并行编程。在实际应用中,还可以探索更复杂的算法和数据结构,并结合 MPI 的高级功能来解决具体问题。