MPI学习

MPI学习前段时间学习了 OpenMP 并且很容易地将其用到了实际应用中 但 OpenMP 也有很多缺点 所有线程共享内存空间 硬件制约较大 目前主要针对循环并行化 为了进一步了解并行计算 MPI 是一个不得不接触的东西 它的优点有 无论硬件是否共享内存空间 都可以使用 与 OpenMP 相比 可以处理规模更大的问题 每个线程都有自己的内存和变量 这样不用担心冲突问题 MPI 的缺点有 算法上经常有较大改动 较难使用 性能上会受到通信网络的影响 1 MPI 简介 MPI 是一个跨语言的通讯协议 用于编写并行计算机 其支持点对点和

  前段时间学习了OpenMP,并且很容易地将其用到了实际应用中,但OpenMP也有很多缺点:所有线程共享内存空间,硬件制约较大;目前主要针对循环并行化。为了进一步了解并行计算,MPI是一个不得不接触的东西。它的优点有:无论硬件是否共享内存空间,都可以使用;与OpenMP相比,可以处理规模更大的问题;每个线程都有自己的内存和变量,这样不用担心冲突问题。MPI的缺点有:算法上经常有较大改动;较难使用;性能上会受到通信网络的影响。

1.MPI简介

MPI是一个跨语言的通讯协议,用于编写并行计算机,其支持点对点和广播。MPI是一个消息传递应用程序接口,包括协议和语义说明,它们指明其如何在各种实现中发挥其特性,目前与MPI绑定的语言只有FORTRAN和C/C++。MPI的目标是高性能,大规模行和可移植性,是一种基于信息传递的并行编程技术。消息传递接口是一种编程接口标准,而不是一种具体的编程语言。简而言之,MPI标准定义了一组具有可移植性的编程接口。

2.MPI环境配置

首先是MPI的下载,最新的MPI已经由微软进行托管,网址如下:http://www.mpich.org/downloads/,来到如下界面,点击http进入。
MPI学习

找到MS-MPI Download部分,选择最新的进行下载:
MPI学习
将两个都选上进行下载:
MPI学习




接下来就是MPI环境的配置,以VS2015为例。首先打开VS,选择文件 — 新建 — 项目 — Visual C++ — win32控制台应用程序。
MPI学习

首先在跳出的界面中选择平台为X64。(最好改为Debug模式来编译运行,因为在后面的代码测试时,release模式下总是会出现无法打开文件msmpi.lib)
MPI学习

进入VC++目录,VC++目录→包含目录,添加:KaTeX parse error: Undefined control sequence: \Microsoft at position 10: (MPI安装位置)\̲M̲i̲c̲r̲o̲s̲o̲f̲t̲ ̲SDKs\MPI\Includ…(MPI安装位置)\Microsoft SDKs\MPI\Lib\x64;其中,$(MPI安装位置)为你安装MPI的位置,如:C:\Program Files (x86)。
MPI学习在这里插入图片描述
选择C/C++ — 预处理器 — “编辑”,添加:MPICH_SKIP_MPICXX
MPI学习




C/C++ →代码生成→运行库,选择:多线程调试(/MTd)。
MPI学习
链接器→输入→附加依赖项,添加:msmpi.lib,就此完成了MPI环境的配置。
MPI学习




3.基础知识

①进程

通俗的说,进程就是运行的程序。一个程序可以含有多个进程,但一个进程不能同属于多个程序。进程拥有独立的运行环境(内存、寄存器、CPU执行时间等),是操作系统中独立存在的可执行的基本单位。每个进程所占有的资源都是独立的,不与其他的进程共享,不能访问其他进程内存空间,其他进程也无法访问该进程内存空间,但可以通过消息传递来进行通信。

②进程组

指一个MPI程序中的所有进程(n个)的集合。该程序中所有进程编号从0到n-1,主要是为了标识不同的进程,可以通过进程的编号来索引该进程。不同进程组的进程的编号可以相同。

③通信器(MPI_Comm)

④ 消息

需要通信的数据

⑤mpi对象

MPI内存的数据结构,包括数据类型(MPI_DOUBLE),通信器(MPI_COMM)等。

⑥mpi数据类型

MPI类型 c类型
MPI_CHAR signed char
MPI_SHORT signed short int
MPI_INT signed int
MPI_LONG signed long
MPI_UNSIGNED_CHAR unsigned char
MPI_UNSIGNED_SHORT unsigned short int
MPI_UNSIGNED unsigned int
MPI_UNSIGNED_LONG unsigned long int
MPI_FLOAT float
MPI_DOUBLE double
MPI_LONG_DOUBLE long double

4.MPI基本函数

① int MPI_Init(int argc,char argv[])

该函数通常应该是第一个被调用的MPI函数用于并行环境初始化,其后面的代码到MPI_Finalize()函数之前的代码在每个进程中都会执行一次。(MPI系统将通过argc,argv得到命令行参数,所以main函数必须带参数,否则会报错)

② int MPI_Finalize(void)

该函数的功能是退出MPI系统,所有进程正常退出都必须调用。表明并行代码的结束,结束除主进程外其他进程。(串行代码仍可在主进程(rank = 0)上运行,但不能再有MPI函数)

① int MPI_Comm_size(MPI_Comm comm,int * size)

该函数的功能是获得进程个数size。(指定一个通信子,也指定了一组共享该空间的进程,这些进程组成该通信子的group,该函数是获取通信子comm中规定的group包含的进程的数量)

④ int MPI_Comm_rank(MPI_Comm comm,int * rank)

该函数的功能是得到本进程在通信空间中的rank值,即在group中的逻辑编号(该rank值为0到p-1间的整数,相当于进程的ID)

⑤ int MPI_Send(void * buf,int count,MPI_Datatype datatype,int dest,int tag,MPI_Comm comm)

该函数为阻塞型发送函数,即等消息发送后才可返回执行下一句。buf为发送区缓存。count为发送的数据的大小。datatype为发送的数据类型。dest为发送的目标进程编号。tag为标志,该标志必须和接收函数的标志一致时才可被接收函数接收。comm通信器。可以理解为buff,count,datatype为消息数据,dest,tag,comm为消息信封。

⑥ int MPI_Recv(void * buf,int count,MPI_Datatype datatype,int source,int tag,MPI_Comm comm,MPI_Status * status)

该函数为阻塞型接收函数,即接收到消息后才可返回执行下一句。buf为接收区缓存,接收区缓存必需大于等于发送的数据。count为接收的数据大小。datatype为接收的数据类型。source为数据的发送源进程编号。tag为标志,该标志必须与发送函数的tag一致才会被接收。comm为通信器。status返回接收状态。

(前六个为最基本的MPI函数,后续的也是一些常用的MPI函数)

int MPI_Initialized(int flag)
该函数用来检测mpi环境是否初始化,唯一可在MPI_Init前使用的函数。

int MPI_Isend(const void * buf, int count, MPI_Datatype datatype, int dest, int tag,MPI_Comm comm, MPI_Request * request);
int MPI_Irecv(void * buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Request * request)
为对应的发送接收函数的非阻塞型函数,即当函数执行后立马返回执行下一行代码,而不需要等待数据正式发送或接收后才可返回。这经常会导致数据的混乱,因此使用非阻塞发送和接收时格外需要注意。



int MPI_Abort(MPI_Comm comm, int errorcode)
异常终止函数。在出现了致命错误而希望异常终止MPI程序时执行,MPI系统会设法终止comm通信器中所有进程, 输入整型参数errorcode,将被作为进程的退出码返回给系统。

int MPI_Get_processor_name(char * name,int * resultlen)
获取处理器名称,在返回的name中存储所在处理器的名称,resultlen存放返回名字所占字节,应提供参数name不少于MPI_MAX_PRCESSOR_NAME个字节的存储空间

int MPI_Get_version(int * version,int * subversion)
获取mpi版本号,若版本为4.0,则version为4,subversion为0。

double MPI_Wtime(void)
返回调用时刻的墙上时间,用浮点数表示秒数

5.MPI简单示例

#include 
     #include 
     #include"mpi.h" int main(int argc,char *argv[]) { 
    int numprocs, myid, source; MPI_Status status; char message[100]; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &myid); MPI_Comm_size(MPI_COMM_WORLD, &numprocs); if (myid != 0) { 
    //非0号进程发送消息 strcpy(message, "Hello world"); MPI_Send(message, strlen(message) + 1, MPI_CHAR, 0, 99, MPI_COMM_WORLD); } else { 
    for (source = 1; source < numprocs; source++) { 
    MPI_Recv(message, 100, MPI_CHAR, source, 99, MPI_COMM_WORLD, &status); printf("接收到第%d号进程发送的消息:%s\n", source, message); } } MPI_Finalize(); //return 0; } 

在这里插入图片描述

6.MPI模型基本结构

//通过上面的代码,我们可以得出MPI模型的基本结构 #include"mpi.h" int main(int argc,char *argv[]) { 
    int rank,size; //初始化MPI环境 MPI_Init(&argc, &argv); //获取进程组中进程编号rank MPI_Comm_rank(MPI_COMM_WORLD, &rank); //获取进程组中进程数size MPI_Comm_size(MPI_COMM_WORLD, &size); ...... //各种操作 ...... //退出MPI环境 MPI_Finalize(); } 
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/204518.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 下午8:08
下一篇 2026年3月19日 下午8:08


相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号