BOOST c++库学习 之 boost.mpi库入门实战指南 以及 使用 boost.mpi库实现进程间通讯(同步与异步的对比)的简单例程

news/2024/9/20 1:26:47/ 标签: c++, 学习, 开发语言, linux, 架构, 嵌入式实时数据库

Boost.MPI 库介绍

1. 概述

Boost.MPI 是 C++ 的 Boost 库中的一个模块,专门用于在分布式内存并行计算中提供消息传递接口。它基于 MPI(Message Passing Interface)标准,旨在简化和提升 C++ 中的分布式计算编程体验。Boost.MPI 封装了传统 MPI 的复杂性,使得开发者可以更自然地在 C++ 中编写高效的并行程序。

2. 与其他进程间通信工具的对比

在分布式计算和多进程通信领域,Boost.MPI 并不是唯一的选择。其他常见的进程间通信(IPC)工具包括传统的 MPI、Boost.Interprocess、POSIX 共享内存和消息队列等。以下是 Boost.MPI 与这些工具的对比分析。

2.1 Boost.MPI vs 传统 MPI
  • 封装性与易用性: 传统的 MPI 是用 C 语言实现的,接口相对较底层且复杂。Boost.MPI 对其进行了 C++ 封装,使得通信过程更加直观和安全,减少了编码中的错误风险。
  • 类型安全: Boost.MPI 在编译时进行类型检查,确保了数据传递的类型安全,而传统 MPI 需要手动管理数据类型,容易引发错误。
  • 自动序列化: Boost.MPI 与 Boost.Serialization 集成,自动处理数据的序列化和反序列化;传统 MPI 则需要手动处理,增加了开发复杂度。
2.2 Boost.MPI vs Boost.Interprocess
  • 使用场景: Boost.Interprocess 专注于单机多进程间的通信,主要使用共享内存、消息队列、信号量等机制,而 Boost.MPI 则专为分布式多节点计算设计,适用于多台计算机之间的进程通信。
  • 通信范围: Boost.Interprocess 适用于同一主机内的进程通信,而 Boost.MPI 则可以在不同的物理节点上进行进程通信。
  • 编程复杂度: Boost.Interprocess 需要开发者手动管理内存和同步,而 Boost.MPI 提供了更高层次的 API,隐藏了许多底层细节。
2.3 Boost.MPI vs POSIX IPC(共享内存、消息队列等)
  • 跨平台支持: POSIX IPC 在 Linux 和类 Unix 系统上表现优异,但在 Windows 上的支持有限。Boost.MPI 作为 Boost 库的一部分,具有良好的跨平台兼容性。
  • 编程模型: POSIX IPC 提供的是底层的通信原语,开发者需要处理复杂的同步和数据管理。Boost.MPI 提供了更高级的抽象,简化了分布式计算中的通信过程。
  • 性能: POSIX IPC 在单机上提供了非常高效的通信方式,适用于高频次、低延迟的进程间通信。而 Boost.MPI 则更多地在多节点环境中提供高效的消息传递功能。
3. Boost.MPI API 简介

Boost.MPI 提供了一系列简洁的 API,用于实现点对点通信、集体通信和异步通信等功能。以下是一些常用的 API:

  • mpi::environment: 初始化和管理 MPI 环境。
  • mpi::communicator: 表示一个通信通道,包含了所有进程的上下文。
  • send/recv: 实现进程间的同步发送和接收操作。
  • broadcast/gather: 提供集体通信功能,如广播数据、收集数据。
  • isend/irecv: 用于异步通信,使进程可以在等待通信完成时继续其他操作。

Boost.MPI 各个接口函数 API 详解以及使用

1. 环境和通信器管理
1.1 mpi::environment

mpi::environment 是 MPI 程序的入口,用于初始化和终止 MPI 环境。它确保在程序开始时正确初始化 MPI,并在程序结束时清理资源。

用法:

#include <boost/mpi.hpp>int main() {mpi::environment env;  // 初始化 MPI 环境// Your MPI code herereturn 0;  // 在 main 函数结束时,自动清理 MPI 环境
}
1.2 mpi::communicator

mpi::communicator 表示一个通信通道或上下文,包含了可以互相通信的一组进程。最常见的通信器是 mpi::communicator world,表示全局通信器,涵盖了所有参与的进程。

常用方法:

  • rank(): 返回当前进程在通信器中的 ID(即进程的排名)。
  • size(): 返回通信器中的进程总数。
  • barrier(): 阻塞所有进程,直到所有进程都到达该点。

示例:

#include <boost/mpi.hpp>
#include <iostream>namespace mpi = boost::mpi;int main() {mpi::environment env;mpi::communicator world;std::cout << "Process " << world.rank() << " of " << world.size() << std::endl;world.barrier();  // 所有进程在此同步return 0;
}
2. 点对点通信
2.1 send

send 函数用于将数据从一个进程发送到另一个进程。数据可以是基本类型,也可以是复杂的自定义数据类型。

语法:

void send(int dest, int tag, const T& value);
  • dest: 目标进程的排名(rank)。
  • tag: 消息标签,用于标识消息类型或目的。
  • value: 要发送的数据,可以是基本类型或支持序列化的类型。

示例:

#include <boost/mpi.hpp>
#include <vector>namespace mpi = boost::mpi;int main() {mpi::environment env;mpi::communicator world;if (world.rank() == 0) {std::vector<int> data = {1, 2, 3, 4, 5};world.send(1, 0, data);}return 0;
}
2.2 recv

recv 函数用于从指定进程接收数据。接收的数据类型必须与发送的数据类型匹配。

语法:

void recv(int source, int tag, T& value);
  • source: 数据来源的进程排名(rank)。
  • tag: 消息标签,与 send 中的标签相匹配。
  • value: 用于存储接收到的数据。

示例:

#include <boost/mpi.hpp>
#include <vector>
#include <iostream>namespace mpi = boost::mpi;int main() {mpi::environment env;mpi::communicator world;if (world.rank() == 1) {std::vector<int> received_data;world.recv(0, 0, received_data);std::cout << "Received data: ";for (int i : received_data) {std::cout << i << " ";}std::cout << std::endl;}return 0;
}
2.3 isendirecv

isendirecv 提供异步通信功能,允许进程在消息传递的同时执行其他任务。

语法:

request isend(int dest, int tag, const T& value);
request irecv(int source, int tag, T& value);
  • 返回值为 request 对象,可以用于检查通信是否完成或等待通信完成。

示例:

#include <boost/mpi.hpp>
#include <vector>
#include <iostream>namespace mpi = boost::mpi;int main() {mpi::environment env;mpi::communicator world;if (world.rank() == 0) {std::vector<int> data = {1, 2, 3, 4, 5};mpi::request req = world.isend(1, 0, data);// 这里可以做其他工作req.wait();  // 等待发送完成} else if (world.rank() == 1) {std::vector<int> received_data;mpi::request req = world.irecv(0, 0, received_data);// 这里可以做其他工作req.wait();  // 等待接收完成std::cout << "Received data: ";for (int i : received_data) {std::cout << i << " ";}std::cout << std::endl;}return 0;
}
3. 集体通信
3.1 broadcast

broadcast 将数据从根进程发送到所有其他进程。根进程的 rank 可以指定。

语法:

void broadcast(T& value, int root);
  • value: 广播的数据;根进程负责提供数据,其他进程接收数据。
  • root: 进行广播的根进程的排名。

示例:

#include <boost/mpi.hpp>
#include <iostream>namespace mpi = boost::mpi;int main() {mpi::environment env;mpi::communicator world;int data;if (world.rank() == 0) {data = 42;  // Root process assigns the value}world.broadcast(data, 0);  // Broadcast data from root (rank 0)std::cout << "Process " << world.rank() << " received data: " << data << std::endl;return 0;
}
3.2 scatter

scatter 将不同的数据块从根进程分发给其他进程。

语法:

void scatter(const T* in_values, T& out_value, int root);
  • in_values: 根进程中的输入数据数组。
  • out_value: 每个进程接收到的输出数据。
  • root: 进行分发的根进程的排名。

示例:

#include <boost/mpi.hpp>
#include <iostream>
#include <vector>namespace mpi = boost::mpi;int main() {mpi::environment env;mpi::communicator world;std::vector<int> send_data;int recv_data;if (world.rank() == 0) {send_data = {10, 20, 30, 40};  // Root process data}world.scatter(send_data.data(), recv_data, 0);std::cout << "Process " << world.rank() << " received: " << recv_data << std::endl;return 0;
}
3.3 gather

gather 从所有进程收集数据到根进程。

语法:

void gather(const T& in_value, std::vector<T>& out_values, int root);
  • in_value: 每个进程要发送的数据。
  • out_values: 根进程接收的所有进程的数据集合。
  • root: 进行收集的根进程的排名。

示例:

#include <boost/mpi.hpp>
#include <iostream>
#include <vector>namespace mpi = boost::mpi;int main() {mpi::environment env;mpi::communicator world;int send_data = world.rank() * 10;std::vector<int> recv_data;world.gather(send_data, recv_data, 0);if (world.rank() == 0) {std::cout << "Process " << world.rank() << " gathered data: ";for (int val : recv_data) {std::cout << val << " ";}std::cout << std::endl;}return 0;
}
3.4 all_gather

all_gather 从所有进程收集数据,并将所有数据分发给每个进程。

语法:

void all_gather(const T& in_value, std::vector<T>& out_values);
  • in_value: 每个进程要发送的数据。
  • out_values: 每个进程接收到的所有进程的数据集合。

示例:

#include <boost/mpi.hpp>
#include <iostream>
#include <vector>namespace mpi = boost::mpi;int main() {mpi::environment env;mpi::communicator world;int send_data = world.rank() * 10;std::vector<int> recv_data;world.all_gather(send_data, recv_data);std::cout << "Process " << world.rank() << " received all data: ";for (int val : recv_data) {std::cout << val << " ";}std::cout << std::endl;return 0;
}
4. 异常处理
4.1 mpi::exception

mpi::exception 是 Boost.MPI 提供的异常类,用于处理 MPI 操作中的错误。这个类继承自 std::runtime_error,可以捕获和处理 MPI 相关的异常。

用法:

#include <boost/mpi.hpp>
#include <iostream>namespace mpi = boost::mpi;int main() {try {mpi::environment env;mpi::communicator world;// Some MPI operation that may fail} catch (mpi::exception& e) {std::cerr << "MPI Exception: " << e.what() << std::endl;}return 0;
}
5. 其他有用的工具
5.1 mpi::reduce

reduce 用于将所有进程的数据进行规约操作,并将结果传递给根进程。常见的操作包括加法、乘法、最大值等。

语法:

void reduce(const T& in_value, T& out_value, Op op, int root);
  • in_value: 每个进程的输入数据。
  • out_value: 根进程接收的规约结果。
  • op: 规约操作,如 mpi::plus<T>() 表示加法。
  • root: 进行规约的根进程的排名。

示例:

#include <boost/mpi.hpp>
#include <iostream>namespace mpi = boost::mpi;int main() {mpi::environment env;mpi::communicator world;int send_data = world.rank();int result;world.reduce(send_data, result, mpi::plus<int>(), 0);if (world.rank() == 0) {std::cout << "Sum of ranks: " << result << std::endl;}return 0;
}
5.2 mpi::all_reduce

all_reducereduce 的扩展,规约操作的结果会被传递给所有进程。

语法:

void all_reduce(const T& in_value, T& out_value, Op op);
  • in_value: 每个进程的输入数据。
  • out_value: 每个进程接收的规约结果。
  • op: 规约操作,如 mpi::plus<T>() 表示加法。

示例:

#include <boost/mpi.hpp>
#include <iostream>namespace mpi = boost::mpi;int main() {mpi::environment env;mpi::communicator world;int send_data = world.rank();int result;world.all_reduce(send_data, result, mpi::plus<int>());std::cout << "Sum of ranks: " << result << " (Process " << world.rank() << ")" << std::endl;return 0;
}

Boost.MPI 异步与同步进程间通信对比测试

下面将演示如何使用 Boost.MPI 实现异步和同步的进程间通信,并对两者进行对比。代码包含两个部分:一个是异步通信的实现,另一个是同步通信的实现。最后,我们将展示如何运行这些测试,并对结果进行分析。

1. 异步通信示例
#include <boost/mpi.hpp>
#include <iostream>
#include <vector>
#include <thread>namespace mpi = boost::mpi;void process_data() {// 模拟一个处理任务,使用线程睡眠表示std::this_thread::sleep_for(std::chrono::seconds(2));
}int main() {mpi::environment env;mpi::communicator world;if (world.rank() == 0) {std::vector<int> data = {1, 2, 3, 4, 5};mpi::request req = world.isend(1, 0, data);std::cout << "Process 0 is doing some other work while sending data..." << std::endl;process_data();  // 模拟其他工作req.wait();  // 等待发送完成std::cout << "Process 0 finished sending data." << std::endl;} else if (world.rank() == 1) {std::vector<int> received_data;mpi::request req = world.irecv(0, 0, received_data);std::cout << "Process 1 is doing some other work while receiving data..." << std::endl;process_data();  // 模拟其他工作req.wait();  // 等待接收完成std::cout << "Process 1 received data: ";for (int i : received_data) {std::cout << i << " ";}std::cout << std::endl;}return 0;
}
2. 同步通信示例
#include <boost/mpi.hpp>
#include <iostream>
#include <vector>namespace mpi = boost::mpi;void process_data() {// 模拟一个处理任务,使用线程睡眠表示std::this_thread::sleep_for(std::chrono::seconds(2));
}int main() {mpi::environment env;mpi::communicator world;if (world.rank() == 0) {std::vector<int> data = {1, 2, 3, 4, 5};world.send(1, 0, data);  // 同步发送std::cout << "Process 0 finished sending data." << std::endl;process_data();  // 发送完成后执行其他工作} else if (world.rank() == 1) {std::vector<int> received_data;world.recv(0, 0, received_data);  // 同步接收std::cout << "Process 1 received data: ";for (int i : received_data) {std::cout << i << " ";}std::cout << std::endl;process_data();  // 接收完成后执行其他工作}return 0;
}
3. 使用步骤
  1. 安装 Boost.MPI:

    • 如果还没有安装 Boost 和 MPI,可以使用以下命令:
      sudo apt-get install libboost-mpi-dev openmpi-bin openmpi-common openmpi-doc libopenmpi-dev
      
  2. 编译代码:

    • 将上述代码分别保存为 async_mpi_test.cppsync_mpi_test.cpp,并使用 mpic++ 编译:
      mpic++ -o async_mpi_test async_mpi_test.cpp -lboost_mpi -lboost_serialization
      mpic++ -o sync_mpi_test sync_mpi_test.cpp -lboost_mpi -lboost_serialization
      
  3. 运行测试:

    • 使用 mpirun 启动两个进程运行异步和同步测试程序:
      mpirun -np 2 ./async_mpi_test
      mpirun -np 2 ./sync_mpi_test
      
4. 测试结果

运行异步通信程序的输出:

Process 0 is doing some other work while sending data...
Process 1 is doing some other work while receiving data...
Process 0 finished sending data.
Process 1 received data: 1 2 3 4 5

运行同步通信程序的输出:

Process 0 finished sending data.
Process 1 received data: 1 2 3 4 5
5. 结果分析
  • 异步通信:

    • 在异步模式下,进程 0 在数据传输过程中可以并行执行其他任务,而不必等待发送完成。类似地,进程 1 在数据到达前也可以执行其他任务。这种方式可以有效利用 CPU 时间,提高并行计算的效率。
    • 异步通信通常适用于需要重叠计算和通信的情况,尤其是在长时间的数据传输或大量数据的情况下。
  • 同步通信:

    • 在同步模式下,进程 0 会等待数据完全发送完毕,然后才开始执行其他任务。进程 1 也会等待数据完全接收完毕,然后再执行其他任务。通信与计算的次序是严格线性的。
    • 同步通信的优点是简单且容易实现,但它可能会导致 CPU 资源的浪费,特别是在通信延迟较大或通信量较大的情况下。
  • 对比:

    • 异步通信在高性能计算中有显著优势,因为它允许计算与通信的重叠,从而最大限度地利用系统资源。
    • 同步通信虽然简单,但可能导致等待时间的增加,进而影响系统整体性能。适用于简单且通信量较少的场景。

通过这些测试,可以直观地看到异步通信如何在程序执行过程中提高效率,尤其是当数据传输时间较长时。

总结

Boost.MPI 是一个强大而易用的库,它封装了传统 MPI 的复杂性,提供了高层次、类型安全和自动序列化的接口,使得 C++ 开发者可以更加专注于算法设计,而无需担心底层通信细节。与其他进程间通信工具相比,Boost.MPI 在分布式多节点计算环境中表现优异,尤其适合需要跨多个物理节点进行通信的应用场景。


http://www.ppmy.cn/news/1511522.html

相关文章

docker数据卷、资源控制

一、docker数据卷&#xff1a; 1.容器和宿主机之间数据共享----挂载卷----容器内的目录和宿主机的目录进行挂载。实现数据文件共享容器的生命周期有限&#xff0c;一旦重启所有对容器内部文件数据的修改以及保存的数据都会被初始化&#xff0c;所以为了防止数据丢失重要的组件…

C++的依赖注入

文章目录 含义实现方式1、构造函数注入&#xff08;Constructor Injection&#xff09;&#xff1a;2、属性注入&#xff08;Setter Injection&#xff09;&#xff1a;3、接口注入&#xff08;Interface Injection&#xff09;&#xff1a; 依赖注入的好处依赖注入的工具 含义…

高性能内存对象缓存Memcached原理与部署

案例概述 Memcached概述 一套开源的高性能分布式内存对象缓存系统所有的数据都存储在内存中支持任意存储类型的数据提高网站的访问速度 数据存储方式与数据过期方式 数据存储方式&#xff1a;Slab Allocation 按组分配内存&#xff0c;每次分配一个Slab&#xff0c;相当于一个…

xss靶场详解

目录 1.第一题 2.第二题 3.第三题 4.第四题 5.第五题 6.第六题 7.第七题 8.第八题 1.第一题 在源码script标签里边&#xff0c;innerhtml是用于访问或修改 HTML 元素内的 HTML 内容的&#xff0c;这里是访问spaghet这个元素的&#xff0c;并通过括号里面的东西搜索当前…

3-1 介绍及传感器(智能应用篇)

3-1 介绍及传感器&#xff08;智能应用篇&#xff09; 3-0 本章介绍3-1 传感器介绍 3-0 本章介绍 Arduino实际应用到生活中 科技创作给生活的乐趣与便利 前两部分内容为基础 太极创客官方网站 课程主角led Led蕴含丰富的科技知识 水立方&#xff0c;led 主机led 汽车le…

广告库存分配与预估方案

在广告投放过程中&#xff0c;有两类问题需要解决&#xff0c;一是库存分配&#xff0c;另一个是库存预估。 一. 库存预估 库存分配的前提是知道当日库存是多少&#xff0c;两个方向可以解决 1. 均值方案 s t o c k s t o c k t − 1 s t o c k t − 2 s t o c k t − 3 …

乾坤qiankun搭建前端微服务

本教程适合于qiankun新手&#xff0c;手把手教你搭建一个简单的本地前端微服务&#xff0c;附完整代码 一、什么是微前端 微前端是一种多个团队通过独立发布功能的方式来共同构建现代化 web 应用的技术手段及方法策略。 微前端架构核心价值&#xff1a; 技术栈无关&#xff1…

StackStorm自动化平台

1. StackStorm概述 1.1 StackStorm介绍 StackStorm是一个开源的事件驱动自动化平台&#xff0c;它允许开发者和系统管理员自动化IT和网络操作。StackStorm结合了IT运维、DevOps和网络安全团队的需求&#xff0c;提供了一个集中式的工作流自动化解决方案&#xff0c;包括事件响…

秋招突击——8/19——知识补全——AQS深入

文章目录 引言正文AQS介绍AQS核心原理不同锁的获取方式 Condition原理await方法signal方法 八股1、获取同步状态的节点&#xff0c;何时移出队列2、公平锁和非公平锁体现在什么地方 总结 引言 之前看过AQS&#xff0c;仅仅是知道他是什么&#xff0c;然后知道哪些方法&#xff…

Go更换国内源配置环境变量

背景 要在中国境内下载和使用Go编程语言的包&#xff0c;可以使用国内的Go模块代理来加速下载速度。以下是一些常见的国内Go模块代理源以及如何切换到这些源的方法&#xff1a; 常见国内Go模块代理源 七牛云&#xff08;Qiniu&#xff09; https://goproxy.cn 阿里云&#xff0…

SVG中的paint-order属性实现文字描边

过去只支持 SVG 元素 paint-order&#xff0c;表示绘制的顺序。 对于一个图形的绘制&#xff0c;顺序还是非常重要的。例如用SVG来绘制一个带边框的矩形 <style>rect{fill: #FFE8A3;stroke: #9747FF;stroke-width: 4;} </style><svg viewBox"0 0 300 30…

【RH134知识点问答题】第7章 管理基本存储

目录 1. 对 Linux 磁盘进行分区时有哪两种方案&#xff1f;分别加以详细说明。 2. 简单说下创建 MBR 磁盘分区涉及哪几个步骤&#xff1f; 3. 创建 GPT 分区与创建 MBR 分区有什么不同&#xff1f; 4. 在创建分区时就会在分区上创建文件系统吗&#xff1f; 5. 如何持久挂载…

mac电脑安装Zsh并启用

安装 Zsh 1. 安装 Zsh 新版mac系统会默认安装并使用zsh&#xff0c;如没用&#xff0c;需在终端中安装&#xff1a; brew install zsh2. 安装 Oh My Zsh 克隆Oh My Zsh到你的目录&#xff1a; git clone https://github.com/robbyrussell/oh-my-zsh.git ~/.oh-my-zsh3. 复…

SpringBoot整合定时任务@Scheduled

SpringBoot自带的定时任务非常简单操作&#xff0c;其实就是一个Scheduled注解。 第一步&#xff1a;创建类&#xff0c;定义执行定时任务的方法 package com.oracle.springboottimer.timer;import org.springframework.scheduling.annotation.Scheduled; import org.springfr…

探索Go语言中的列表与环形缓冲区:container/list与container/ring全解析

标题&#xff1a;探索Go语言中的列表与环形缓冲区&#xff1a;container/list与container/ring全解析 在Go语言的丰富标准库中&#xff0c;container/list和container/ring提供了列表和环形缓冲区的实现&#xff0c;这些数据结构对于处理序列数据和实现高效的生产者-消费者队列…

所生成项目的处理器架构“MSIL”与引用“***”的处理器架构“x86”不匹配。

在c#工程里新建了一个类库&#xff0c;编译的场合出现以下警告&#xff1a;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\amd64\Microsoft.Common.CurrentVersion.targets(2401,5): warning MSB3270: 所生成项目的处理器架构“MSIL”与引用“…

Qt五大核心特性之对象模型

前言 在开始之前我查阅对象模型的资料的时候发现一搜标题是对象模型&#xff0c;但是内容是对象树&#xff0c;这俩又不是一个东西&#xff0c;而且还不是一个人这么写。 正文 对象模型&#xff08;Object Model&#xff09; 对象模型是指 Qt 中 QObject 提供的一种基本编程…

Python爬虫入门教程(非常详细)适合零基础小白

一、什么是爬虫&#xff1f; 1.简单介绍爬虫 爬虫的全称为网络爬虫&#xff0c;简称爬虫&#xff0c;别名有网络机器人&#xff0c;网络蜘蛛等等。 网络爬虫是一种自动获取网页内容的程序&#xff0c;为搜索引擎提供了重要的数据支撑。搜索引擎通过网络爬虫技术&#xff0c;将…

在 Go 语言中,字符串格式化拼接可以通过多种方法实现

在 Go 语言中&#xff0c;字符串格式化拼接可以通过多种方法实现。以下是几种常见的方法&#xff1a; 1. 使用 fmt.Sprintf 使用 fmt 包的 Sprintf 函数格式化字符串。 package mainimport ("fmt" )func main() {name : "Alice"age : 30str : fmt.Sprin…

Unity | 游戏开发中的优化思维

目录 ​​​​​​一、优化三板斧&#xff1a; 第1步&#xff1a;定标准 第2步&#xff1a;重数据 第3步&#xff1a;严测试 二、流程和性能的优化 1.定标准&#xff1a; 2.重数据&#xff1a; 三、交互和表现的优化 1.卡顿和延迟 2.手感硬 四、沟通和学习 ​​​​…