还是按照以前写blog的三部曲思路:先列出相应的知识要点与原理解释,再记录操作中遇到的疑惑与问题及其解答与解决方案,最后谈谈感想。

  • 首先介绍一下MPI背景与一个简单例子

MPI全称是message passing interface,即信息传递接口,是用于跨节点通讯的基础软件环境。它提供让相关进程之间进行通信,同步等操作的API,可以说是并行计算居家出游必备的基础库。

一个 MPI 程序包含若干个进程。每个 mpi 进程都运行一份相同的代码,进程的行为由通讯域(communication world)和该通讯域下的 id(rank id)所决定。

MPI的编程方式,是“一处代码,多处执行”。编写过多线程的人应该能够理解,就是同样的代码,不同的进程执行不同的路径。

那么怎么区分不同的进程呢?

MPI有几个常用的API,其中有一个叫做MPI_Comm_rank, 它返回调用它的进程的具体进程号。比如我启动了10个进程,然后每个进程的这个调用会返回0-9对应的进程编号。这样它们就知道谁是老大,谁是老二,谁是老九……于是我们可以很确定地下命令,让老大去买菜,老二到老五洗中午的碗碟,老六到老九准备做饭。

要想运行MPI并行程序,使用普通的编译器是不行的,需要使用特殊的mpi编译器。其实所谓的mpi编译器,只是普通的编译器外加了个套件。比如mpicxx,就是在g++外面套了个mpi的壳。而且除了编译器要用特殊的编译器之外,运行时还要用特殊的程序,比如mpiexec和mpirun。

这里澄清一下,虽然mpiexec和mpirun除了前缀其他各不相同,但是它们不是两兄弟,只是一个程序的不同说法罢了……
具体的运行方法,是mpirun -n x ./myProgram,其中x是要启动的进程数。这时候,如果你使用系统监视器或者终端下的top命令,应该能够看到x个名字一模一样的进程正嘿哟嘿哟地运行着。

前面讲到的MPI_Comm_rank调用,返回的值为0到x-1中的一个值,取决于对应的进程是老大还是老x。



  • 简单例子:主要功能是随机打印(每次运行结果都不相同)各进程的id号
#include <iostream>
#include "mpi.h"

using namespace std;

int main(int argc, char* argv[]) {
  MPI::Init(argc, argv);
  int l_proc = MPI::COMM_WORLD.Get_size();
  int l_rank = MPI::COMM_WORLD.Get_rank();

  cout<< "Total Rank: " << l_proc << endl
    << "My Rank: " << l_rank << endl;
  MPI::Finalize();
  return 0;
}



编译后在集群上运行输出情况:

[stu5785@cluster mpihw]$ mpirun -n 8 ./mpihw
Total Rank: 8
My Rank: 2
Total Rank: 8
My Rank: 3
Total Rank: 8
My Rank: 6
Total Rank: 8
My Rank: 0
Total Rank: 8
My Rank: 4
Total Rank: 8
My Rank: 7
Total Rank: 8
My Rank: 5
Total Rank: 8
My Rank: 1



那么问题来了(学挖掘机哪家强~^_^~)


问题1:

MPI启动命令mpiexec和mpirun之间有什么区别?

stackoverflow有一个不错的回答:

mpiexec is defined in the MPI standard (well, the recent versions at least) and I refer you to those (your favourite search engine will find them for you) for details.

mpirun is a command implemented by many MPI implementations. It has never, however, been standardised and there have always been, often subtle, differences between implementations. For details see the documentation of the implementation(s) of your choice.

And yes, they are both used to launch MPI programs, these days mpiexec is generally preferable because it is standardised.



另一个比较深入的回答是:MPI常用命令(里面设计到了mpd的概念,为方便理解,见MPICH2 user guide)

mpiexec: 
MPI程序运行命令,运行前必须开启mpd守护进程。 
常用形式: 
       mpiexec <g-options> <l-options> <executable> 
       mpiexec <g-options> <l-options> <executable> 
       mpiexec –configfile <file> 
其中,
       <g-options>  全局选项运用于所有MPI进程。 
       <l-options>  本地选项应用于部分MPI进程集合。 
       <executable> 可执行文件的路劲。 
       <file>       包含命令行选项的文件。 
全局选项中常用参数:
        -gdb 调试运行 
        -machinefile <file> MPI进程分配文件。 
本地选项中常用参数:
        -n num 设置执行MPI程序的进程总数 
注意:全局选项和本地选项顺序不要弄错。


问题2:

openmpi与mpich的区别?(两者都是mpi的实现)

具体回答间链接:mpich VS openmpi