ubuntu下配置MPI环境及使用示例

MPICH

MPI(Message Passing Interface)是高性能和广泛可移植的消息传递接口,它是一种标准或规范的代表,而不是一门语言或特指某一个对它的具体实现。MPICH是MPI准的一种实现,它与MPI-1规范同步发展的版本,每当MPI推出新的版本,就会有相应的MPICH的实现版本。MPICH性能卓越,在2016年6月的排名中,排名前10的超级计算机中有9台使用了该系统,其中包括世界上运行速度最快的超级计算机:太湖之光。

环境配置

Linux与Windows皆可配置MPI环境,但Windows下配置更为繁琐麻烦,本着能少做就不做的原则,故最终选择Ubuntu系统。1(Windows下配置参考这里

  1. 下载
    可以直接在MPICH的官方网站下载对应的源码包,由于其官网在国外以及一些众所周知的原因,直接下载的速度可能会比较慢或者失败,这里可以使用已经下载好的源码包mpich-3.3.2.tar.gz
  2. 依赖安装
    如果你是用的是崭新的ubuntu系统的话,可能得先使用sudo apt upgrade更新系统并安装一些依赖sudo apt install gcc g++ gfortran make
  3. 编译安装
    将源码上传到ubuntu中并解压,然后进入到解压目录中打开命令行,以此执行以下命令:
    • ./configurate
    • make
    • sudo make install
  4. enjoy it!
    理论上来讲以上命令执行完后你便可使用mpiccmpirun等命令,途中如果失败可以看一下错误信息,大多是缺少依赖或是权限不足等简单问题,自己处理一下即可。 https://cdn.jsdelivr.net/gh/wefantasy/FileCloud/img/20201205205123.png

简单示例

mpiexec -n 10 ./hello #在当前设备中创建10个进程,执行hello

向根进程致敬

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <stdio.h>
#include "mpi.h"
#include <string.h>
int main(int argc, char *argv[])
{
	int numprocs; /*进程数,该变量为各处理器中的同名变量, 存储是分布的*/
	int myid; /*我的进程ID,存储也是分布的*/
	int source; /*发送消息的源进程 */
	MPI_Status status; /*消息接收状态变量,存储也是分布的*/
	char message[100]; /*消息 buffer,存储也是分布的*/
	int namelen; /*定义进程名长度*/
	char processor_name[MPI_MAX_PROCESSOR_NAME]; /*定义进程名*/
	MPI_Init(&argc, &argv); /*初始化MPI*/
	MPI_Comm_rank(MPI_COMM_WORLD, &myid); /*各进程得到自己进程号*/
	MPI_Comm_size(MPI_COMM_WORLD, &numprocs); /*各进程得到进程数*/
	MPI_Get_processor_name(processor_name, &namelen); /*取进程名*/
	if (myid != 0) {
		/*建立消息*/
		strcpy(message, "Hello friend!");
		/*发送长度取 strlen(message)+1, 使\0也一同发送出去*/
		MPI_Send(message, strlen(message) + 1, MPI_CHAR, 0, 99, MPI_COMM_WORLD);
	}
	else { /* my_rank == 0 */
		for (source = 1; source < numprocs; source++)
		{
			MPI_Recv(message, 100, MPI_CHAR, source, 99, MPI_COMM_WORLD, &status);
			printf("%s\n", message);
			
		}
	}
	printf("%s\n",processor_name);
	/*关闭MPI,标志并行代码段的结束*/
	MPI_Finalize();
} 

聚合求π

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <stdio.h>
#include <mpi.h>
int main(int argc, char *argv[])
{
	int my_rank, num_procs;
	int i, n = 0;
	double sum, h, x, mypi, pi;
	double start = 0.0, stop = 0.0;
	int namelen;
	char processor_name[MPI_MAX_PROCESSOR_NAME];

	MPI_Init(&argc, &argv);
	MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
	MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
	MPI_Get_processor_name(processor_name, &namelen);

	n = 200000;
	MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD);
	h = 1.0 / (double)n;
	sum = 0.0;

	//每个进程my_rank,计算4.0/(1.0+x*x)放入sum
	for (i = my_rank; i < n; i += num_procs)
	{
		x = h * ((double)i + 0.5);
		sum += 4.0 / (1.0 + x * x);
	}
	mypi = h * sum;
	MPI_Reduce(&mypi, &pi, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
	//打印结果
	if (my_rank == 0)
	{
		printf("PI is %.20f\n", pi);
		printf("on %s\n", processor_name);
	}
	MPI_Finalize();
	return 0;
}

指定进程交换数据

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include<stdio.h>
#include"mpi.h"
int main(int argc, char*argv[])
{
	int rank, size, tag1 = 1, tag2 = 2;
	int senddata1, recvdata1, senddata2, recvdata2;
	int namelen;
	char processor_name[MPI_MAX_PROCESSOR_NAME];    /*定义进程名*/
	MPI_Status status;
	MPI_Init(&argc, &argv);
	MPI_Comm_size(MPI_COMM_WORLD, &size);
	MPI_Comm_rank(MPI_COMM_WORLD, &rank);
	MPI_Get_processor_name(processor_name, &namelen);
	if (rank == 0){
		senddata1 = 123;
		MPI_Send(&senddata1, 1, MPI_INT, 1, tag1, MPI_COMM_WORLD);
		MPI_Recv(&recvdata2, 1, MPI_INT, 1, tag2, MPI_COMM_WORLD, &status);
		fprintf(stderr, "process %d of %d on %s\n", rank, size, processor_name);
		printf("proc 0 receiveproc 1 :  recvdata1 = %d\n", recvdata2);
	}
	else if (rank == 1){
		MPI_Recv(&recvdata1, 1, MPI_INT, 0, tag1, MPI_COMM_WORLD, &status);
		senddata2 = 456;
		MPI_Send(&senddata2, 1, MPI_INT, 0, tag2, MPI_COMM_WORLD);
		fprintf(stderr, "process %d of %d on %s\n", rank, size, processor_name);
		printf("proc 1 receive proc 0 value :  recvdata2 = %d\n", recvdata1);
	}
	MPI_Finalize();
	return 0;
}

参考


  1. 青杏了了. ubuntu中的MPI安装. CSDN. [2020-07-20] ↩︎