MPI
MPI(Message Passing Interface)是一种用于编写并行程序的标准和库,用于在分布式内存系统中进行消息传递和并行计算。MPI提供了一组函数和语义,用于在多个进程之间进行通信和同步,以实现并行计算和并行任务的协调。MPI在高性能计算领域被广泛应用,用于开发并行和分布式内存计算应用程序。它提供了丰富而强大的功能,使得开发者能够充分利用并行计算资源,提高计算效率和性能。MPI有很多种实现。MPICH是其中的MPI实现之一。
MPI安装
MPICH官网:https://www.mpich.org/downloads/
tar -zvxf mpich-4.1.2.tar.gz
cd mpich-4.1.2
./configure --disable-fortran
make -j 10
sudo make install
在源码包的examples文件夹下有测试程序,可进行编译测试:
#include <stdio.h>
#include "mpi.h"int main(int argc, char *argv[])
{int rank;int size;MPI_Init(0, 0);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;
}
mpicc hellow.c -o hellow
mpiexec -n 5 ./hellow
如果安装了anaconda,出现/home/fakerth/anaconda3/bin/mpicc: 行 323: x86_64-conda-linux-gnu-cc: 未找到命令,
使用conda deactivate退出anaconda环境,再进行编译。
MPI函数
1.MPI_Init:
函数原型:MPI_Init(int *argc, char ***argv)
功能:初始化MPI环境,必须在所有MPI函数之前调用。
参数:argc和argv是main函数的参数,用于传递命令行参数。
注意事项:每个进程都需要调用MPI_Init函数,通过MPI_COMM_WORLD通信域进行初始化。
2.MPI_Finalize:
函数原型:MPI_Finalize()
功能:终止MPI环境,必须在程序结束前调用。
注意事项:每个进程都需要调用MPI_Finalize函数,通过MPI_COMM_WORLD通信域进行终止。
3.MPI_Comm_size:
函数原型:MPI_Comm_size(MPI_Comm comm, int *size)
功能:获取指定通信域中的进程数量。
参数:comm是通信域,通常使用MPI_COMM_WORLD表示全局通信域;size是一个指针,返回通信域中的进程数量。
4.MPI_Comm_rank:
函数原型:MPI_Comm_rank(MPI_Comm comm, int *rank)
功能:获取当前进程在指定通信域中的进程ID(排名)。
参数:comm是通信域,通常使用MPI_COMM_WORLD表示全局通信域;rank是一个指针,返回当前进程在通信域中的进程ID。
5.MPI_Send:
函数原型:MPI_Send(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm)
功能:将数据发送给其他进程。
参数:buf是发送缓冲区的起始地址;count是发送的数据个数;datatype是发送的数据类型;dest是目标进程的ID;tag是消息标签;comm是通信域。
6.MPI_Recv:
函数原型:MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status)
功能:接收来自其他进程发送的数据。
参数:buf是接收缓冲区的起始地址;count是接收的数据个数;datatype是接收的数据类型;source是源进程的ID;tag是消息标签;comm是通信域;status是一个结构体指针,用于返回接收消息的状态信息。
π的计算
#include <iostream>
#include "mpi.h"
using namespace std;int main(int argc, char**argv)
{//mpirun -np 4 calculatePI.o 800 其中的800是以参数的形式传入的,位于argv[1]long double pi=0, answer=0, PI=3.141592653589793238462643383279;int size, id, namelen,n=1000;double time;char processor_name[MPI_MAX_PROCESSOR_NAME];MPI_Status status;//如果参数列表中制定了n的值,则将该值赋给nif(argc==2)sscanf(argv[1], "%d", &n);MPI_Init(&argc, &argv);//开始计时time=MPI_Wtime();//获取进程信息MPI_Comm_size( MPI_COMM_WORLD , &size);MPI_Comm_rank( MPI_COMM_WORLD , &id);//比较n和size大小,若n过小,则返回if(n<size){cout<<"输入n值过小, 请重新输入"<<endl;MPI_Finalize();return 0;}for(int i=id; i<=n; i+=size){long double tempans;tempans = (long double)1/(long double)(2*i+1);if(i%2==0){answer+=tempans;}else{answer-=tempans;}}//如果是主进程if(id==0){long double recvbuf;pi=answer;for(int i=1; i<size; i++){MPI_Recv( &recvbuf , 1 , MPI_LONG_DOUBLE , MPI_ANY_SOURCE , 0 , MPI_COMM_WORLD , &status);pi+=recvbuf;}}else//发送消息并退出程序{MPI_Send( &answer , 1 , MPI_LONG_DOUBLE , 0 , 0 , MPI_COMM_WORLD);MPI_Finalize();return 0;}pi*=4;cout<<"主进程使用"<<MPI_Wtime()-time<<"秒, 最后得到PI的计算结果为: ";printf("%.20Lf\n",pi); cout<<"n = "<<n<<" 使用了 "<<MPI_Wtime()-time <<"s pi = ";printf("%.20Lf %.20Lf \n",pi,abs(PI-pi)); MPI_Finalize();return 0;
}
C++用mpicxx编译,感受一个进程和八个进程的计算时间: