并行计算之MPI简介以及基本通信案例(阻塞,非阻塞)

news2024/11/19 7:43:32

MPI是什么

Message Passing Interface 是一种消息传递编程模型,是这种模型的代表和事实上的标准,用于编写并行程序。主要思想是将一个程序分解为多个进程,这些进程相互通信并协作完成任务。MPI可以在多台计算机或者多个计算节点上执行,还可以利用不同的通信机制进行进程间的通信。

由2022年图灵将获得者----Jack j.dongarra发起。

是一种新的库描述,不是一种语言,共有上百个函数调用接口,提供C和Fortran语言;

MPI是一种标准,规范的代表,而不是具体实现,当前所有的并行计算机制造商都提供对MPI的支持:

  1. Intel MPI
  2. Open MPI
  3. mpich

MPI应用场景

主要应用于高性能计算和分布式计算领域,如

  • 科学计算,如天体物理学,量子化学,材料科学,加速复杂的计算和模拟;
  • 海量数据处理,并行加速处理大规模数据集的过程,如图像处理,信号处理,机器学习和深度学习;
  • 工程模拟,如用于工程领域的模拟和优化,例如计算流体力学,有限元分析,结构学力学等,用来加速数值计算和仿真。

Linux环境准备

我的是ubuntu20.04,以下是OpenMPI环境安装过程:

sudo apt-get install openmpi-bin libopenmpi-dev

编写Hello World程序

#include "mpi.h"
#include <iostream>

int main(int argc, char *argv[])
{
    int err = MPI_Init(&argc,&argv);
    std::cout << "MPI Hello World" << std::endl;
    err = MPI_Finalize();
    return 0;
}

编译程序,需要使用MPI自带的编译器,而不是GCC/G++,使用起来和GCC/G++差不多,底层调用的还是这些编译器。

mpic++ main.cpp -o a.out

运行程序,需要依赖可执行程序mpirun

mpirun -np 2 a.out

其中 -np 指定启动进程(一般为后台进程)的个数,该数字和你机器配置相关,建议小于CPU数量或物理核心数。

这里将打印出2个 "MPI Hello World"

MPI常用接口

  1. 消息传递接口, 如MPI_Send 和 MPI_Receive 等,用于实现进程之间的点对点通;
  2. 阻塞与非阻塞接口,上述MPI_Send 和 MPI_Receive是阻塞接口,MPI提供了MPI_Isend 和 MPI_Irecv 等接口,提供非阻塞的通信方式;
  3. 广播和全局操作接口:MPI_Bcast 和 MPI_Scatter 接口用于广播和分发数据,而 MPI_Reduce 和 MPI_Allreduce 接口则用于执行聚合操作;
  4. 数据类型接口,提供了一些用于定义各种数据类型的接口,如 MPI_Datatype 和 MPI_Type_contiguous,用于支持更复杂的数据通信和操作;
  5. 包括上述代码示例中,用于进程管理和性能调试的接口,如 MPI_Init 环境初始化 和 MPI_Finalize 环境结束等。
  6. MPI_Comm_rank,获取当前进程在指定通信域中的进程标识符;
int rank;
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
  1. MPI_Comm_size:获取指定通信域(包括 MPI_COMM_WORLD 和自定义的通信域)中进程的总数;
int size;
MPI_Comm_size(MPI_COMM_WORLD, &size);
  1. MPI_Comm_split:根据指定的颜色信息,将指定通信域中的进程分隔成多个子通信域,并返回分隔后的新通信域;
  2. MPI_Comm_dup:复制指定通信域,返回一个新的通信域;
  3. MPI_Comm_free:释放指定通信域的内存资源,并将通信域设为 MPI_COMM_NULL
  4. MPI_Comm_create:通过指定的进程标识符和通信域,创建一个新的通信域
  5. MPI_Comm_spawn:在指定的通信域中新建一个或多个进程,并返回每个新进程的通信域
  6. MPI_Intercomm_create:在两个指定的通信域之间创建一个新的“互联通信域”,用于实现不同通信域之间的通信。

通信域:

MPI 中一组可能需要进行通信的进程的逻辑结构。通信域中的每个进程都有一个唯一的标识符(通信域内部的秩/等级(rank)),并可以通过指定目标进程的标识符来对目标进程进行通信。不同通信域的进程不能直接进程通信,但是,可以通过MPI_Intercomm_create将两个不通的域合并为一个互联的通信域,同时返回在每个通信域中所代表的所有进程的通信域标识符和秩

MPI定义了几个默认的通信域:

  • MPI_COMM_WORLD 多进程所有进程,缺省的通信域名,可以通过MPI_Comm_rank获取进程在这个通信域中的rank值;
  • MPI_COMM_SELF 单进程的通信域,应用于如只与自身通信的特殊作用域;

举个例子

#include "mpi.h"
#include <unistd.h>
#include <iostream>


int main(int argc, char *argv[])
{
    int err = MPI_Init(&argc,&argv);
    int rank,size;
    //获取当前进程在通信域中的rank值
    MPI_Comm_rank(MPI_COMM_WORLD,&rank);
    //获取当前通信域的进程总数
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    std::cout << "Hello World from process " << rank << " of " << size << std::endl;
    //环境清理,必须加,否则MPI程序不结束
    err = MPI_Finalize();
    return 0;
}

编译执行:mpirun -np 2 a.out

Hello World from process 1 of 2
Hello World from process 0 of 2

MPI的并行模式

主从模式

拥有一个主进程,主进程作为任务的分配方,从进程执行任务,主进程负责管理数据的分发和接受;
在这里插入图片描述

SPMD

Single Program Multiple Data 该模式下,多个进程运行同一个程序,但每个进程处理不同的数据。这种模式是最常见和最基础的并行模式,MPI_COMM_WORLD 通信域通常被用来实现这种模式

MPMD

Multiple Program Multiple Data 该模式下,多个进程在不同的程序中运行,每个进程独立地执行不同的任务。这种模式适用于需要针对特定问题进行优化的情况,MPI_Comm_spawn 通信接口可以用来生成子进程

数据并行

数据被分割为多个子数据块,每个进程处理其中的一部分数据块,进程之间通过数据传输进行协作。数据并行是实现大规模并行化的经典模式,MPI_Send 和 MPI_Recv 等接口可用于实现数据传输

任务并行

各进程运行相同的程序,但处理不同的任务。进程协作完成整个任务,在任务的不同阶段,每个进程执行不同的功能。任务并行又可以细分为 pipeline 并行、模块并行、工作站并行等模式

流水线并行

任务被划分为多个阶段,在每个阶段中,数据沿着流水线被处理,不同的进程专门处理不同的阶段。这种模式适用于有序处理数据的场景,可以提高并行程序的效率。

模块并行

该模式将一个程序分成若干个子任务,每个子任务由不同的进程执行。不同的子任务之间具有依赖关系,需要通过数据传输和同步操作来完成计算。

非同步并行

进程之间没有明确的同步,机制,各自执行独立的子任务,进程之间通过消息传递进行通信。适用于简单问题和小规模的并行计算。

MPI通信

点对点通信

用于一个进程和一个接收进程之间的数据交互,有分为阻塞和非阻塞通信模式。

在这里插入图片描述

阻塞接口

int MPI_Send(void *buf, int count, MPI_Datatype datatype, int dest, int tag/*消息标签*/, MPI_Comm comm)
int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status)

非阻塞接口

int MPI_Isend(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)

在这里插入图片描述

判断通信是否完成:

MPI_Wait 函数的作用是等待一个非阻塞式 MPI 通信操作(如 MPI_Isend 和 MPI_Irecv)完成,直到其请求对象进入完成状态为止。如果请求对象尚未完成,则 MPI_Wait 函数会阻塞当前进程的执行,直到请求对象的状态为完成状态才返回。MPI_Wait 函数的用法如下:

int MPI_Wait(MPI_Request *request, MPI_Status *status)

MPI_Test 函数的作用与 MPI_Wait 函数类似,都是等待一个请求对象进入完成状态,但 MPI_Test 函数是非阻塞的,即当请求对象尚未完成时,MPI_Test 函数会立即返回一个标志值,而不会阻塞当前进程的执行。MPI_Test 函数的用法如下:

int MPI_Test(MPI_Request *request, int *flag, MPI_Status *status)

消息类型

  1. 基本数据类型(Primitive data types):包括 MPI_CHAR、MPI_SHORT、MPI_INT、MPI_LONG、MPI_UNSIGNED_CHAR、MPI_UNSIGNED_SHORT、MPI_UNSIGNED、MPI_UNSIGNED_LONG、MPI_FLOAT、MPI_DOUBLE等,可以用于传输常见的数据类型和数值类型;
  2. 复杂数据类型(Derived data types):包括 MPI_DATATYPE、MPI_ARRAY、MPI_STRUCT 等,可以用于传输由多个变量组成的结构化数据类型
  3. 特殊数据类型:包括 MPI_PACKED 等,可用于封装任意类型的数据
  4. 自定义数据类型:MPI 还提供了自定义数据类型的支持,用户可以根据实际需要定义自己的数据类型,并将其注册到 MPI 环境中,以供后续使用

阻塞通信代码示例

//0号进程给1号进程发送数据
#include "mpi.h"
#include <unistd.h>
#include <iostream>


int main(int argc, char *argv[])
{
    int err = MPI_Init(&argc,&argv);
    int rank,size;
    MPI_Comm_rank(MPI_COMM_WORLD,&rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    if(0 == rank)
    {
        int sendNum = 99;
        int tag = 0;
        MPI_Send(&sendNum, 1 ,MPI_INT ,1 , tag , MPI_COMM_WORLD);
    }
    else
    {
        int recvNum = 0;
        int tag = 0;
        MPI_Status status;
        std::cout << "before recv , recv num = " << recvNum << std::endl;
        MPI_Recv(&recvNum, 1 ,MPI_INT , 0, tag, MPI_COMM_WORLD, &status);
        std::cout << "before recv , recv num = " << recvNum << std::endl;
    }
    
    err = MPI_Finalize();
    return 0;
}

非阻塞通信代码示例

int main(int argc, char *argv[])
{
    int err = MPI_Init(&argc,&argv);
    int rank,size;
    MPI_Comm_rank(MPI_COMM_WORLD,&rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    int data = 100;
    MPI_Request request;
    MPI_Status status;



    if(rank > 0)
    {   
        MPI_Irecv(&data,1,MPI_INT,rank-1,0,MPI_COMM_WORLD,&request);
        std::cout << "rank = " << rank << " recived data is :  " << data << std::endl;
        MPI_Wait(&request, &status);
        std::cout << "rank = " << rank << " recived data is :  " << data << std::endl;
    }

    
    if(rank < size - 1)
    {
        data = rank;
        MPI_Isend(&data,1,MPI_INT, (rank + 1)%size, 0 ,MPI_COMM_WORLD, &request);
        MPI_Wait(&request, &status);
    }
    
    err = MPI_Finalize();
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/946230.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

js中forEach和map的区别:forEach不会改变原数组,而map会改变数组?错了错了

1.提出思考&#xff1f;forEach不会改变原数组&#xff0c;而map会改变数组&#xff1f; 看到掘金上一篇文章觉得很有意思&#xff1a;大致是描述一般面试官问js中forEach和map的区别&#xff1f;都会回答forEach不会改变原数组&#xff0c;而map会改变&#xff0c;我也一直对…

理虚实一体化全栈全场景云计算应用实训室解决方案

一、 云计算应用统概述 云计算应用系统是指基于云计算技术构建的应用系统&#xff0c;它将软件、数据、计算和存储资源部署在云服务器上&#xff0c;通过网络根据应用按照一定策略为用户提供相关服务。云计算应用系统广泛应用于各个领域&#xff0c;包括但不限于金融、教育、政…

buildAdmin的使用笔记

安装buildAdmin 下载完整包&#xff0c;解压进入 buildadmin 的文件夹&#xff0c; 输入命令 composer install 启动的时候使用&#xff0c; php think run 就可以了 为什么启动只需要&#xff0c; php think run 这种启动方式&#xff0c; 我是头一回看见 &#xff0c;后来才…

数据结构:单向循环链表

单向循环链表和单向链表差不多&#xff0c;只需要记录头节点的位置把单向链表判断NULL的地方改为判断头节点即可 dxxhlb.h dxxhlb.cmain.c 结果

五、多表查询-4.4子查询-行子查询

一、概述 子查询返回的结果是一行&#xff08;可以是多列&#xff09;&#xff0c;这种子查询称为行子查询。 常用的操作符&#xff1a;、<>、in、not in 二、演示 【例】查询与“张无忌”的薪资及直属领导相同的员工信息 1、查询张无忌的薪资和直属领导 返回的结果是…

Android Activity启动过程一:从Intent到Activity创建

关于作者&#xff1a;CSDN内容合伙人、技术专家&#xff0c; 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 &#xff0c;擅长java后端、移动开发、人工智能等&#xff0c;希望大家多多支持。 目录 一、概览二、应用内启动源码流程 (startActivity)2.1 startActivit…

Windows 在 Hyper-V 上 安装Win11系统

文章目录 一、Hyper-V 介绍1. Hyper-V 简介2. 系统要求3. 启动 Hyper-V方式1&#xff1a;通过 PowerShell 启动方式2&#xff1a;通过设置启动 二、安装Win11虚拟机1. 在搜索栏搜索并打开Hyper-V 管理器2. 快速创建 或 新建>虚拟机3. 创建虚拟机4. 编辑设置5. 启动虚拟机6. …

华为云云服务器评测|华为云云耀云服务器L实例使用教学

文章目录 教学小故事 教学 华为云云耀云服务器L实例是一款提供高效、可靠、安全的基础设施服务的云服务器。下面是使用教学&#xff1a; 登录华为云官网。 测评产品链接&#xff1a;https://www.huaweicloud.com/product/hecs-light.html 进入云耀云服务器管理控制台&#xf…

机器学习笔记之核函数再回首:Nadarya-Watson核回归python手写示例

机器学习笔记之核函数再回首——Nadaraya-Watson核回归手写示例 引言回顾&#xff1a; Nadaraya-Watson \text{Nadaraya-Watson} Nadaraya-Watson核回归通过核函数描述样本之间的关联关系使用 Softmax \text{Softmax} Softmax函数对权重进行划分将权重与相应标签执行加权运算 N…

CVE-2023-38831 WinRAR 逻辑漏洞原因分析

简介 漏洞编号&#xff1a;CVE-2023-38831漏洞类型&#xff1a;逻辑漏洞软件名称&#xff1a;RARLAB WinRAR模块名称&#xff1a;WinRAR.exe历史漏洞&#xff1a;根据 vuldb 显示&#xff0c;历史漏洞并不是很多&#xff0c;能稳定利用的更是少之又少 CISA 已知漏洞利用目录中…

【pyqt5界面化开发-3】工具图标设置

一、目标1&#xff1a;添加icon图标 需要模块&#xff1a;from PyQt5.QtGui import QIcon w.setWindowIcon(QIcon(C:\\img_path\\test.png)) 代码(自己加上自己的图标路劲)&#xff1a; import sysfrom PyQt5.QtGui import QIcon from PyQt5.QtWidgets import QApplication,…

基于Web的旅游推荐网站设计与实现(论文+源码)_kaic

【摘 要】 当前&#xff0c;众所周知的旅游产业已慢慢成为全世界经济领域中最具代表影响力和最大领域的产业之一&#xff0c;互联网的蓬勃发展也为旅游业带来了新的机遇。并且旅游网站已经逐渐成为管理旅游信息的主要模式。因此&#xff0c;开发一个稳定性良好、可用性强的旅游…

串口联网通信数据监听视监控侦测协议规约破解方案

作为物联网数据采集解决方案专业提供商,数采物联网小编daq-iot 在这里做以下内容介绍,并诚挚的欢迎大家讨论和交流。 本方案主要用于监听和侦测 串口通信数据报文&#xff0c;主要用于协议报文分析 破解领域。 例如破解摄像头控制道闸开启的命令等。 监控和分析通信数据代表的含…

常用的Splunk命令

查看版本 splunk version 状态、启动、停止、重启 splunk status|start|stop|restart 关闭/开启splunk服务 net stop splunkd net start splunkd 查看管理端口 splunk show splunkd_port 查看web端口 splunk show web_port 更改端口 splunk set web_port 7897 查看监听 s…

leetcode 42. 接雨水

2023.8.29 本题可以用双指针做&#xff0c;求出每一列能盛的雨水&#xff0c;再相加即可。不过暴力法会超时&#xff0c;需要优化。 双指针&#xff08;暴力&#xff09;&#xff1a; class Solution { public:int trap(vector<int>& height) {int ans 0;for(int …

加强版python连接飞书通知——本地电脑PC端通过网页链接打开本地已安装软件(调用注册表形式,以漏洞扫描工具AppScan为例)

前言 如果你想要通过超链接来打开本地应用,那么你首先你需要将你的应用添入windows注册表中(这样网页就可以通过指定代号来调用程序),由于安全性的原因所以网页无法直接通过输入绝对路径来调用本地文件。 一、通过创建reg文件自动配置注册表 创建文本文档,使用记事本打开…

ssm削面快餐店点餐服务系统源码和论文

ssm削面快餐店点餐服务系统源码和论文080 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm 随着互联网技术的快速发展&#xff0c;网络时代的到来&#xff0c;网络信息也将会改变当今社会。各行各业在日常企业经…

Python+win32gui将Excel文件xlsx批量快速转换xls(附完整代码+全注释)

&#x1f338; 欢迎来到Python办公自动化专栏—Python处理办公问题&#xff0c;解放您的双手 &#x1f3f3;️‍&#x1f308; 博客主页&#xff1a;一晌小贪欢的博客主页 &#x1f44d; 该系列文章专栏&#xff1a;Python办公自动化专栏 文章作者技术和水平有限&#xff0c…

【第四阶段】kotlin语言的解构语法过滤元素

1.list集合的解构操作 package Stage4fun main() {val list listOf("java","kotlin","c")//元素解构var(v1,v2,v3)listprint("v1$v1,v2$v2,v3$v3") }执行结果 2.将上述代码转化为Java代码 使用Java 代码需要大量书写 3.解构过滤元…