MPI安装与程序设计

发布时间:2023年12月22日

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的值,则将该值赋给n
    if(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编译,感受一个进程和八个进程的计算时间:
在这里插入图片描述

文章来源:https://blog.csdn.net/weixin_43912621/article/details/135157375
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。