MPI之通信模式(标准,缓存,同步,就绪)
MPI缓冲区
- 由MPI自行维护的一块内存区域,也可由用户(MPI_Bsend)自行维护;
- 发送方 维护一块发送缓冲区; 接收方 维护一块接收缓冲区。
数据收发过程:
- 当发送端将数据拷贝到自身的数据缓冲区后(注意这里是拷贝,即数据到达发送缓冲区,再对原数据进行修改将不会影响发送的数据),对应的Send函数将会返回,意味着发送动作已经完成;
- 当接收端将数据拷贝到自身的接收缓冲区中,Recv函数调用结束。
类似于Socket通信时,调用send将数据放置发送缓冲区即表示send完成。
阻塞通信模型
发送
1. 标准通信模式 MPI_Send 该接口是否进行缓存由MPI决定,分情况讨论
- 发送进程的发送动作不依赖接收进程(有缓存):发送进程将数据拷贝到数据缓冲区,不管接收进程有没有执行接收动作,函数都直接返回,发送动作对于用户来讲已经完成;
- 发送进程的发送动作依赖于接收进程(不带缓存,直接发送):发送进程发送消息时需要接收进程也要开始接收进程,两者处于一边发送一边接收的状态,此时MPI_Send阻塞当前发送方直到数据被接收方确认收到,基于底层的数据传输机制;
2. 缓存通信模式 MPI_Bsend 当用户对上述标准通信模式不满意,不能满足需求,可以采用该模式
该函数在发送消息时使用明确的缓冲区,并具有较低的内存使用率和较高的性能。相对于 MPI_Send 函数,MPI_Bsend 不阻塞发送方,也不会复制消息缓冲区中的数据,而是将数据拷贝到MPI缓冲区中,MPI_Bsend 函数将立即返回,在MPI缓冲区中的消息稍后使用异步方式传输。
函数原型
int MPI_Bsend(const void *buf, int count,
MPI_Datatype datatype, int dest, int tag, MPI_Comm comm)
//用户自行管理缓冲区
int MPI_Buffer_attach(void *buffer,int size)
int MPI_Buffer_detach(void *buffer,int &size)
参数详解
- buf: 待发送数据的首地址
- count: 待发送的数据量
- datatype: 待发送数据类型
- dest: 目标进程的 MPI rank
- tag: 消息标记
- comm: MPI通信域
注意事项
发送时需要将数据从消息缓冲区拷贝到用户提供的缓冲区buffer,该方法消除了发送端同步的开销,如前面分析,消息发送能否进行及能否正确返回不依赖于接收进程。好处是用户可以认为程序需要发送的消息提供缓冲区,但用户也需要负责管理该缓冲区。如果该缓冲区buffer大小不足以存储消息缓冲区中待发送的数据,将导致程序错误退出。
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>#define BUFFER_SIZE 1024int main(int argc, char *argv[])
{int rank, size;MPI_Status status;double t0, t1;char buf[BUFFER_SIZE];char *my_buffer;MPI_Request request;MPI_Init(&argc, &argv);MPI_Comm_rank(MPI_COMM_WORLD, &rank);MPI_Comm_size(MPI_COMM_WORLD, &size);if(rank == 0){//为MPI缓冲区分配内存空间my_buffer=(char *)malloc(BUFFER_SIZE);MPI_Buffer_attach(my_buffer, BUFFER_SIZE);snprintf(buf, BUFFER_SIZE, "Hello, world, from rank %d!", rank);t0=MPI_Wtime();//异步发送消息MPI_Bsend(buf, BUFFER_SIZE, MPI_CHAR, 1, 0, MPI_COMM_WORLD, &request);MPI_Wait(&request, &status);t1=MPI_Wtime();printf("Time taken=%f\n", t1-t0);free(my_buffer);MPI_Buffer_detach(&my_buffer, &BUFFER_SIZE);}else{//为MPI缓冲区分配内存空间my_buffer=(char *)malloc(BUFFER_SIZE);MPI_Buffer_attach(my_buffer, BUFFER_SIZE);t0=MPI_Wtime();//等待接收消息MPI_Recv(buf, BUFFER_SIZE, MPI_CHAR, 0, 0, MPI_COMM_WORLD, &status);t1=MPI_Wtime();printf("Rank %d received message=%s, time=%f\n", rank, buf, t1-t0);free(my_buffer);MPI_Buffer_detach(&my_buffer, &BUFFER_SIZE);}MPI_Finalize();return 0;
}
3. 同步通信模式 MPI_Ssend
该模式的开始不依赖接收进程相应的接收操作是否已经启动,但是同步发送却必须等到相应的接收进程开始后才可以正确返回。即
- 发送方必须等待接收方的确认才能继续执行。
- 接收方必须收到消息后才能继续执行。
- 可以确保接收方正确接收消息。
函数原型
int MPI_Ssend(void* buf, int count, MPI_Datatype datatype,
int dest, int tag, MPI_Comm comm)
参数详解
- buf:指向待发送数据的指针。
- count:发送元素数量。
- datatype:发送元素的类型。
- dest:目标进程的进程号。
- tag:消息标签。
- comm:进程通信域
代码示例
#include <stdio.h>
#include <mpi.h>int main(int argc, char** argv) {int size, rank;int data;MPI_Status status;MPI_Init(&argc, &argv);MPI_Comm_size(MPI_COMM_WORLD, &size);MPI_Comm_rank(MPI_COMM_WORLD, &rank);
if (rank == 0) {data = 12345;MPI_Ssend(&data, 1, MPI_INT, 1, 0, MPI_COMM_WORLD);printf("Process 0 sent data %d to process 1\n", data);} else if (rank == 1) {MPI_Recv(&data, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &status);printf("Process 1 received data %d from process 0\n", data);}MPI_Finalize();return 0;
}
4. 就绪通信模式 MPI_Rsend
该模式只有当接收进程的接收操作已经启动时才可以在发送进程启动发送操作(即是一种发送并立即返回操作),否则,当发送操作启动而相应的操作还没有启动时,发送操作将出错,对于非阻塞发送操作的正确返回,并不意味着发送已经完成,但对于阻塞发送的正确返回,则代表发送缓冲区可以重复使用。
函数原型
int MPI_Rsend(const void *buf, int count, MPI_Datatype datatype,
int dest, int tag, MPI_Comm comm)
参数详解
- buf:指向待发送数据的指针。
- count:发送元素数量。
- datatype:发送元素的类型。
- dest:目标进程的进程号。
- tag:消息标签。
- comm:进程通信域
代码实例
#include <stdio.h>
#include <mpi.h>int main(int argc, char** argv) {int size, rank;int data;MPI_Status status;MPI_Init(&argc, &argv);MPI_Comm_size(MPI_COMM_WORLD, &size);MPI_Comm_rank(MPI_COMM_WORLD, &rank);if (rank == 0) {data = 12345;MPI_Request request;MPI_Rsend(&data, 1, MPI_INT, 1, 0, MPI_COMM_WORLD);printf("Process 0 sent data %d to process 1\n", data);} else if (rank == 1) {MPI_Status status;int data_recv;MPI_Recv(&data_recv, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &status);printf("Process 1 received data %d from process 0\n", data_recv);}MPI_Finalize();return 0;
}
接收
- MPI_Recv
非阻塞通信模式
发送
标准通信模式 MPI_Isend
缓存通信模式 MPI_Ibsend
是 MPI_Bsend 的非阻塞版本,在 MPI_Bsend 的基础上,MPI_Ibsend 函数允许发送方在消息发送期间继续执行其他操作,而不必等待消息发送完成。MPI_Ibsend 函数将消息存储在缓冲区中,并返回一个 MPI_Request 对象,代表着消息的发送请求。
函数原型
int MPI_Ibsend(const void* buf, int count,
MPI_Datatype datatype, int dest, int tag,
MPI_Comm comm, MPI_Request* request)
参数详解
- buf:指向待发送数据的指针。
- count:发送元素数量。
- datatype:发送元素的类型。
- dest:目标进程的进程号。
- tag:消息标签。
- comm:进程通信域。
- request:MPI_Request 类型的指针,存储发送请求对象。
代码实例
#include <stdio.h>
#include <mpi.h>#define BUFFER_SIZE 1024int main(int argc, char** argv) {int size, rank;int data;MPI_Status status;char buffer[BUFFER_SIZE];MPI_Request request;MPI_Init(&argc, &argv);MPI_Comm_size(MPI_COMM_WORLD, &size);MPI_Comm_rank(MPI_COMM_WORLD, &rank);if (rank == 0) {data = 12345;MPI_Buffer_attach(buffer, BUFFER_SIZE);MPI_Ibsend(&data, 1, MPI_INT, 1, 0, MPI_COMM_WORLD, &request);printf("Process 0 sent data %d to process 1\n", data);MPI_Wait(&request, &status);MPI_Buffer_detach(buffer, &BUFFER_SIZE);} else if (rank == 1) {int data_recv;MPI_Recv(&data_recv, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &status);printf("Process 1 received data %d from process 0\n", data_recv);}MPI_Finalize();return 0;
}
同步通信模式 MPI_Issend
MPI_Ssend 的非阻塞版本,在 MPI_Ssend 的基础上,MPI_Issend 函数允许发送方在消息发送期间继续执行其他操作,而不必等待消息发送完成。MPI_Issend 函数将消息存储在缓冲区中,并返回一个 MPI_Request 对象,代表着消息的发送请求。
函数原型
int MPI_Issend(const void* buf, int count,
MPI_Datatype datatype, int dest, int tag,
MPI_Comm comm, MPI_Request* request)
参数详解
- buf:指向待发送数据的指针。
- count:发送元素数量。
- datatype:发送元素的类型。
- dest:目标进程的进程号。
- tag:消息标签。
- comm:进程通信域。
- request:MPI_Request 类型的指针,存储发送请求对象。
代码实例
#include <stdio.h>
#include <mpi.h>#define BUFFER_SIZE 1024int main(int argc, char** argv) {int size, rank;int data;MPI_Status status;char buffer[BUFFER_SIZE];MPI_Request request;MPI_Init(&argc, &argv);MPI_Comm_size(MPI_COMM_WORLD, &size);MPI_Comm_rank(MPI_COMM_WORLD, &rank);if (rank == 0) {data = 12345;MPI_Buffer_attach(buffer, BUFFER_SIZE);MPI_Issend(&data, 1, MPI_INT, 1, 0, MPI_COMM_WORLD, &request);printf("Process 0 sent data %d to process 1\n", data);MPI_Wait(&request, &status);MPI_Buffer_detach(buffer, &BUFFER_SIZE);} else if (rank == 1) {int data_recv;MPI_Recv(&data_recv, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &status);printf("Process 1 received data %d from process 0\n", data_recv);}MPI_Finalize();return 0;
}
就绪通信模式 MPI_Irsend
是 MPI_Rsend 的非阻塞版本,在 MPI_Rsend 的基础上,MPI_Irsend 函数允许发送方在消息发送期间继续执行其他操作,而不必等待消息发送完成。MPI_Irsend 函数将消息存储在缓冲区中,并返回一个 MPI_Request 对象,代表着消息的发送请求。
函数原型
int MPI_Irsend(const void* buf, int count,
MPI_Datatype datatype, int dest, int tag,
MPI_Comm comm, MPI_Request* request)
参数详解
- buf:指向待发送数据的指针。
- count:发送元素数量。
- datatype:发送元素的类型。
- dest:目标进程的进程号。
- tag:消息标签。
- comm:进程通信域。
- request:MPI_Request 类型的指针,存储发送请求对象。
代码实例
#include <stdio.h>
#include <mpi.h>#define BUFFER_SIZE 1024int main(int argc, char** argv) {int size, rank;int data;MPI_Status status;char buffer[BUFFER_SIZE];MPI_Request request;MPI_Init(&argc, &argv);MPI_Comm_size(MPI_COMM_WORLD, &size);MPI_Comm_rank(MPI_COMM_WORLD, &rank);if (rank == 0) {data = 12345;MPI_Buffer_attach(buffer, BUFFER_SIZE);MPI_Irsend(&data, 1, MPI_INT, 1, 0, MPI_COMM_WORLD, &request);printf("Process 0 sent data %d to process 1\n", data);MPI_Wait(&request, &status);MPI_Buffer_detach(buffer, &BUFFER_SIZE);} else if (rank == 1) {int data_recv;MPI_Recv(&data_recv, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &status);printf("Process 1 received data %d from process 0\n", data_recv);}MPI_Finalize();return 0;
}
注,MPI_Irsend 的缓冲区大小由 MPI_BSEND_BUFFER_SIZE 宏定义所决定。如果发送的消息大于缓冲区大小,将会导致 MPI_Irsend 函数阻塞
接收
- MPI_Irecv
区别:
- 是否要对发送的数据进行缓存;(缓存)
- 是否只有当接收调用执行后才可以执行发送操作;(同步)
- 什么时候发送调用可以正确返回;
- 发送调用正确返回是否意味着发送已完成。
几种特殊使用场景
短时间内有大量的短消息的发送
可能会导致缓冲区爆掉,导致消息丢失,用户可能需要使用MPI_Bsend控制缓冲区的使用;
如果短消息可以打包成一个大消息,降低发送次数
发送的数据量特别大
MPI提供的缓冲区的大小不够,可能导致数据丢失,从而导致程序卡,MPI_Bsend模式来直接控制缓冲区的使用;
可以进行分段发送,对数据进程拆分。
相关文章:

MPI之通信模式(标准,缓存,同步,就绪)
MPI缓冲区 由MPI自行维护的一块内存区域,也可由用户(MPI_Bsend)自行维护;发送方 维护一块发送缓冲区; 接收方 维护一块接收缓冲区。 数据收发过程: 当发送端将数据拷贝到自身的数据缓冲区后(注意这里是拷贝,即数据到…...

面试官:说一下 MyBatis 的一级缓存和二级缓存 ?
目录 1. MyBatis 的缓存机制 2. 为什么不默认开启 MyBatis 的二级缓存 3. MyBatis 如何开启二级缓存 4. MyBatis 有哪些缓存清除策略 1. MyBatis 的缓存机制 MyBayis 中包含两级缓存:一级缓存和二级缓存 1. 一级缓存是 SqlSession 级别的,是 MyBati…...
Ajax与jQuery
目录 Ajax是一种异步无刷新的技术 Ajax的优点: 可以无需刷新页面与服务器端进行通信允许根据用户事件来更新部分页面内容 Ajax的缺点: 没有浏览历史,不能回退存在跨域问题(同源)SEO(搜索引擎优化&#x…...

色温曲线坐标轴的选取:G/R、G/B还是R/G、B/G ?
海思色温曲线坐标 Mstar色温曲线坐标 高通色温曲线坐标 联咏色温曲线坐标 查看各家白平衡调试界面,比如海思、Mstart、高通等调试资料,白平衡模块都是以R/G B/G作为坐标系的两个坐标轴,也有方案是以G/R G/B作为坐标系的两个坐标轴。 以G/R G…...

maven部署
一、下载Maven 地址:Maven – Download Apache Maven 二、解压缩,设置环境变量 tar -xvf apache-maven-3.8.8-bin.tar.gz export MAVEN_HOME/opt/apache-maven-3.8.8 export PATH$MAVEN_HOME/bin:$PATH echo $MAVEN_HOME echo $PATH mvn -v...
docker进阶作业
一、使用mysql:5.6和 owncloud 镜像,构建一个个人网盘。 安装Docker:确保已在CentOS 7.5上安装了Docker。 拉取MySQL 5.6镜像:使用以下命令从Docker Hub上拉取MySQL 5.6镜像。 docker pull mysql:5.6 运行MySQL容器:使用以下命令…...

HTML+JavaScript+CSS DIY 分隔条splitter
一、需求分析 现在电脑的屏幕越来越大,为了利用好宽屏,我们在设计系统UI时喜欢在左侧放个菜单或选项面板,在右边显示与菜单或选项对应的内容,两者之间用分隔条splitter来间隔,并可以通过拖动分隔条splitter来动态调研…...
Oracle-day5:新增、复制建表、表结构、表数据、删除
目录 一、insert新增数据 二、复制建表 三、表结构修改 四、查看表结构、表数据处理 五、修改表数据 六、删除语句 八、练习题 一、insert新增数据 /* ---------- 一、DML 数据操作语言-------- -- 1、增加数据 insert 语法:insert into 表名 (列1,列2,…...

Scratch 画画的技巧
前言 美术是一种艺术,且不局限于纸张,就像电脑绘图也属于美术。我至今已有三年多的画龄,经验丰富,尤其擅长在scratch造型编辑器上画矢量图。今天给大家分享一些实用的技巧。 1.讲解 用橡皮工具给一个圆擦出“橡皮洞” 橡皮工具&a…...
国际版阿里云/腾讯云:阿里弹性云手机正式公测
阿里弹性云手机正式公测 什么是“云手机”?与我们传统的手机有何区别?它又有什么用处呢?当你接触到云手机概念的时候,是不是也会有这一连串的疑问。本文将为你揭开云手机的奥秘面纱。 2021年12月1日,阿里弹性云手机正…...

服务器数据恢复- RAID5出现故障后恢复数据和操作系统的案例
服务器数据恢复环境: 某品牌服务器中有4块SAS硬盘组建了一组RAID5阵列,另外1块磁盘作为热备盘使用。上层操作系统为redhat linux,部署了一个数据库是oracle的OA。 服务器故障&初检: RAID5中一块磁盘离线后热备盘未自动激活re…...

Vue3实现可视化拖拽标签小程序
介绍 实现功能:可视化标签拖拽,双击标签可修改标签内容 HTML结构 <div class"box" v-move><div class"header">标签1</div><div dblclick"startEditing" v-if"!isEditing">{{content…...
SSM 前端使用AJAX方式,fromdata文件格式上传二进制流文件
今天在上课的时候,遇到了一个比较坑的问题,有个学生拿来了她的代码,让我给她看看为什么传值传不过来。 首先,前端是这样的: function upload(){var formData new FormData();formData.append(images, $(#previewImg)…...

LeetCode-455-分发饼干-贪心算法
题目描述: 假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。 对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 jÿ…...
新版 Next.js 从入门到入土
本教程用的Next.js 是 13 版本 Next.js 简介 完善的React项目,搭建轻松自带数据同步,解决服务端渲染最大难点丰富的插件灵活配置 创建第一个项目 手动创建 初始化 npm init安装所需要的依赖包 npm install --save react react-don next增加快捷命…...

OpenCV(十):图像缩放、翻转、拼接的介绍与使用
目录 (1)图像缩放:resize() (2)图像翻转: flip() (3)图像拼接:hconcat() 和vconcat() (1)图像缩放:resize() 使用 cv2.resize() 函…...

C++ 学习之 构造函数 和 析构函数
前言 总的来说,构造函数负责对象的初始化,而析构函数负责对象的清理和资源释放。它们是C面向对象编程中非常重要的概念,用于管理对象的生命周期,确保对象在创建和销毁时都能够正确地进行初始化和清理。 正文 看代码 class perso…...
加快 MySQL 数据迁移
目录 一、先导 1. 自建目标实例 2. 配置目标主从 二、源导出 1. 生成查询用户权限的SQL语句 2. 生成权限的SQL语句 3. 生成创建非主键索引的SQL语句 4. 导出源库结构 5. 导出源库数据 三、目标导入 1. 目标实例设置 2. 创建用户与权限 3. 处理结构导出文件 4. 导…...

CANalyzer panel
(1205条消息) CAPL 脚本中对信号,系统变量,环境变量的 事件响应_capl programs脚本怎么写信号运算_蚂蚁小兵的博客-CSDN博客 注意环境变量是在工程关联的dbc中创建的;而系统变量是在CANoe工程工具栏的”Environment”下的”System Variables”…...

延迟队列的理解与使用
目录 一、场景引入 二、延迟队列的三种场景 1、死信队列TTL对队列进行延迟 2、创建通用延时消息死信队列 对消息延迟 3、使用rabbitmq的延时队列插件 x-delayed-message使用 父pom文件 pom文件 配置文件 config 生产者 消费者 结果 一、场景引入 我们知道可以通过TT…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...
Spring是如何解决Bean的循环依赖:三级缓存机制
1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间互相持有对方引用,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

深度学习水论文:mamba+图像增强
🧀当前视觉领域对高效长序列建模需求激增,对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模,以及动态计算优势,在图像质量提升和细节恢复方面有难以替代的作用。 🧀因此短时间内,就有不…...

淘宝扭蛋机小程序系统开发:打造互动性强的购物平台
淘宝扭蛋机小程序系统的开发,旨在打造一个互动性强的购物平台,让用户在购物的同时,能够享受到更多的乐趣和惊喜。 淘宝扭蛋机小程序系统拥有丰富的互动功能。用户可以通过虚拟摇杆操作扭蛋机,实现旋转、抽拉等动作,增…...

MySQL:分区的基本使用
目录 一、什么是分区二、有什么作用三、分类四、创建分区五、删除分区 一、什么是分区 MySQL 分区(Partitioning)是一种将单张表的数据逻辑上拆分成多个物理部分的技术。这些物理部分(分区)可以独立存储、管理和优化,…...