系列文章目录
- 初探MPI——MPI简介
- 初探MPI——点对点通信
- 初探MPI——集体通信
文章目录
- 系列文章目录
- 前言
- 一、MPI_COMM_WORLD, size and ranks
- 二、Hello World
- Instructions
- 总结
- 参考
前言
Message Passing Interface (MPI) 是一种标准化的消息传递库接口规范。该标准是消息传递模型的一种标准,该标准大量运用在科学计算领域。详尽的介绍参看MPI Tutorials。
一、MPI_COMM_WORLD, size and ranks
当一个程序使用MPI运行时,所有进程都被分组到一个叫通信器(communicator)中,它们之间能相互通信。每个通信都链接到一个通信器,允许通信到达不同的进程。通信有两种类型:
- 点对点(point to point)通信 Two processes in the same communicator are going to communicate.
- 集体性(collective)通信All the processes in a communicator are going to communicate together.
默认通信器叫MPI_COMM_WORLD
,它对程序启动时的所有进程进行分组。看下面的例子,一个程序,它运行了五个进程。每个进程都是相互连接的,并且可以在此通信器内进行通信。
MPI_COMM_WORLD
不是 MPI 中唯一的通信者。在接下来的章节中介绍如何创建自定义通信器,但目前,让我们坚持使用 MPI_COMM_WORLD
.在接下来的章节中,每次提到communicator时,只需将其替换为 MPI_COMM_WORLD
.
communicator中的号码在创建后不会更改。该数字称为communicator的大小(size)。同时,communicator中的每个进程都有一个唯一的编号来识别它。此数字称为进程的秩(rank)。在前面的示例中,MPI_COMM_WORLD
的size为 5。每个进程的rank是每个圆圈内的数字。进程的秩始终在 0 到 size - 1 之间 。
二、Hello World
编写一个跨多个进程的简单Hello World代码
首先,MPI必须初始化(initialised)和结束(finalised)。**这两个操作必须始终是代码的第一次和最后一次调用。**现在关于这两个操作没有太多可说的,我们只是说他们是程序的setup。
MPICH 实现文档,它警告我们:
The MPI standard does not say what a program can do before an MPI_INIT or after an MPI_FINALIZE.
In the MPICH implementation, you should do as little as possible.
In particular, avoid anything that changes the external state of
the program, such as opening files, reading standard input or writing to standard output.
因此,按照惯例,这两个命令在程序中始终被调用为第一个和最后一个。对应的命令是 MPI_Init
和 MPI_Finalize
。 MPI_Init
总是引用命令行参数,而 MPI_Finalize
不接受。因此,在 C++ 中,它们的签名如下:
int MPI_Init(int *argc, char ***argv);
int MPI_Finalize();
获得rank和size的方法,遵循以下调用:
int size, rank;
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
请注意 MPI_COMM_WORLD
. MPI_COMM_WORLD
这表明该操作是在封装了当前运行的每个进程的全局通信器上完成的。我们稍后将看到什么是通信器以及如何创建它们以创建流程组。目前,我们将坚持在本章的 WORLD 通信器上调用 MPI。
Instructions
- Initialises MPI.
- Reads the rank of the current process on MPI_COMM_WORLD.
- Prints Hello world, from process #<RANK OF THE PROCESS.
- Finalizes MPI and exits.
#include <iostream>
#include <mpi.h>
int main(int argc, char** argv) {
// Initialisation
MPI_Init(&argc, &argv);
// Reading size and rank
int world_rank;
MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
// Printing
std::cout << "Hello world, from process #" << world_rank << std::endl;
// Finalisation
MPI_Finalize();
return 0;
}
运行结果:
在本地机器上运行需要注意,有一种简单的方法可以编译 MPI 代码。安装任何实现(如 OpenMPI 或 MPICH)时,都会提供wrapper compilers。如果要在安装 OpenMPI 发行版后编译此代码,则必须替换简单的编译器行:
g++ -o hello_world hello_world.cpp
替换为下面编译指令
mpicxx -o hello_world hello_world.cpp
有三种这样的包装器可以用 MPI 实现主要支持的三种语言进行编译:C、C++ 和 Fortran。相应的包装器是 : mpicc 和 mpicxx mpifort 。请注意,这些命令只是包装器,它们将使用环境变量调用编译器。通过 --show 使用命令行参数,可以看到使用这些编译器之一时实际执行的行。例如,在相当标准的 Linux 安装中, mpicxx --show 将返回如下内容:
g++ -I/usr/local/include -pthread -Wl,-rpath -Wl,/usr/local/lib -Wl,--enable-new-dtags -L/usr/local/lib -lmpi_cxx -lmpi
编译程序后,可以使用该 mpirun
命令跨多个进程运行该程序
mpirun -np 4 ./hello_world
总结
- MPI简介,消息传递模型
- global communicator
- rank 和 size
- 初始化和结束
- 使用MPI进行简单的hello world小程序编写
参考
- Introduction to MPI
- MPI Tutorials