C++ Boost MPI接口详细讲解

目录
  • 一、说明
  • 二、开发和运行时环境
  • 三、简单数据交换

一、说明

Boost.MPI 提供了 MPI 标准(消息传递接口)的接口。该标准简化了并发执行任务的程序的开发。您可以使用线程或通过共享内存或网络连接使多个进程相互通信来开发此类程序。 MPI 的优点是你不需要关心这些细节。您可以完全专注于并行化您的程序。

缺点是您需要 MPI 运行时环境。如果您控制运行时环境,MPI 只是一个选项。例如,如果你想分发一个可以通过双击启动的程序,你将无法使用 MPI。虽然操作系统开箱即用地支持线程、共享内存和网络,但它们通常不提供 MPI 运行时环境。用户需要执行额外的步骤来启动 MPI 程序。

  • 开发和运行时环境
  • 简单的数据交换
  • 异步数据交换
  • 集体数据交换

二、开发和运行时环境

MPI 定义了用于并行计算的函数。并行计算是指在支持任务并行执行的运行时环境中可以并发执行任务的程序。这样的运行时环境通常基于多个处理器。由于单个处理器只能顺序执行代码,因此链接多个处理器会创建一个可以并行执行任务的运行时环境。如果连接了数千个处理器,结果就是一台并行计算机——一种通常只在超级计算机中才能找到的架构。 MPI 来自于寻找更容易地为超级计算机编程的方法的搜索。

如果你想使用 MPI,你需要一个标准的实现。虽然 MPI 定义了许多功能,但它们通常不受开箱即用的操作系统支持。例如,Windows 的桌面版本不附带 MPI 支持。

最重要的 MPI 实现是 MPICH 和 Open MPI。 MPICH 是最早的 MPI 实现之一。它自 1990 年代中期就已存在。 MPICH 是一种成熟且可移植的实现,并得到积极维护和更新。 Open MPI 的第一个版本于 2005 年发布。由于 Open MPI 是一项协作成果,其中包括许多负责早期 MPI 实现的开发人员,因此 Open MPI 被视为未来的标准。然而,这并不意味着可以忽略 MPICH。有几种基于 MPICH 的 MPI 实现。例如,Microsoft 发布了一个名为 Microsoft HPC Pack 的 MPI 实现,它基于 MPICH。

MPICH 为各种操作系统(如 Windows、Linux 和 OS X)提供安装文件。如果您需要 MPI 实现并且不想从源代码构建它,MPICH 安装文件是开始使用 MPI 的最快途径。

MPICH 安装文件包含开发 MPI 程序所需的头文件和库。此外,它们还包含一个 MPI 运行时环境。因为 MPI 程序同时在多个处理器上执行任务,所以它们在多个进程中运行。一个 MPI 程序会启动多次,而不仅仅是一次。同一 MPI 程序的多个实例在多个处理器上运行,并通过 MPI 标准定义的函数进行通信。

您无法通过双击启动 MPI 程序。您使用一个帮助程序,通常称为 mpiexec。您将 MPI 程序传递给 mpiexec,它会在 MPI 运行时环境中启动您的程序。命令行选项确定启动了多少个进程以及它们如何通信——例如,通过套接字或共享内存。因为 MPI 运行时环境会处理这些细节,所以您可以专注于并行编程。

如果您决定使用 MPICH 的安装文件,请注意 MPICH 仅提供 64 位版本。您必须使用 64 位编译器通过 MPICH 开发 MPI 程序并构建 64 位版本的 Boost.MPI。

三、简单数据交换

Boost.MPI 是 MPI 标准的 C++ 接口。该库使用命名空间 boost::mpi。包含头文件 boost/mpi.hpp 就足以访问所有类和函数。

示例 47.1。 MPI 环境和通信器

#include <boost/mpi.hpp>
#include <iostream>
int main(int argc, char *argv[])
{
  boost::mpi::environment env{argc, argv};
  boost::mpi::communicator world;
  std::cout << world.rank() << ", " << world.size() << '\n';
}

Example47.1

示例 47.1 是一个简单的 MPI 程序。它使用两个类,您将在随后的所有示例中找到它们。 boost::mpi::environment 初始化 MPI。构造函数从 MPI 标准调用函数 MPI_Init()。析构函数调用 MPI_Finalize()。 boost::mpi::communicator 用于创建通信器。通信器是 MPI 的核心概念之一,支持进程之间的数据交换。

boost::mpi::environment 是一个非常简单的类,只提供了几个成员函数。您可以调用 initialized() 检查 MPI 是否已成功初始化。成员函数返回一个 bool 类型的值。 processor_name() 以 std::string 的形式返回当前进程的名称。 abort() 会停止 MPI 程序,而不仅仅是当前进程。您将一个 int 值传递给 abort()。该值将作为 MPI 程序的返回值传递到 MPI 运行时环境。对于大多数 MPI 程序,您不需要这些成员函数。您通常在程序开始时实例化 boost::mpi::environment,然后不使用该对象——如示例 47.1 和本章中的以下示例。

boost::mpi::communicator 更有趣。此类是一个通信器,它链接作为 MPI 程序一部分的进程。每个进程都有一个等级,它是一个整数——所有进程都会被枚举。进程可以通过在通信器上调用 rank() 来发现其等级。如果进程想知道有多少个进程,它会调用 size()。

要运行示例 47.1,您必须使用您正在使用的 MPI 实现提供的帮助程序。对于 MPICH,辅 助程序称为 mpiexec。您可以通过以下命令使用此帮助程序运行示例 47.1:

mpiexec-n4sample.exe

mpiexec 需要一个 MPI 程序的名称和一个告诉它要启动多少进程的选项。选项 -n 4 告诉 mpiexec 启动四个进程。因此 MPI 程序启动了四次。但是,这四个过程并不是独立的。它们通过 MPI 运行时环境链接,并且它们都属于同一个通信器,这给每个进程一个等级。如果您使用四个进程运行示例 47.1,rank() 返回一个从 0 到 3 的数字和 size() 4。

请注意,输出可能会混淆。毕竟,有四个进程同时写入标准输出流。例如,不知道排名为 0 或任何其他排名的进程是否是第一个写入标准输出流的进程。也有可能一个进程在写入标准输出流时会中断另一个进程。在另一个进程写入标准输出流之前,被中断的进程可能无法完成写入其等级和通信器的大小,从而破坏输出。

示例 47.2。发送和接收数据的阻塞函数

#include <boost/mpi.hpp>
#include <iostream>
int main(int argc, char *argv[])
{
  boost::mpi::environment env{argc, argv};
  boost::mpi::communicator world;
  if (world.rank() == 0)
  {
    int i;
    world.recv(1, 16, i);
    std::cout << i << '\n';
  }
  else if (world.rank() == 1)
  {
    world.send(0, 16, 99);
  }
}

boost::mpi::communicator 提供了两个简单的成员函数,send() 和 recv(),用于在两个进程之间交换数据。它们是阻塞函数,仅在发送或接收数据时才返回。这对于 recv() 尤其重要。如果在没有其他进程向其发送数据的情况下调用 recv(),调用将阻塞并且进程将在调用中停止。

在示例 47.2 中,等级为 0 的进程使用 recv() 接收数据。等级为 1 的进程使用 send() 发送数据。如果你用两个以上的进程启动程序,其他进程什么都不做就直接退出。

您将三个参数传递给 send():第一个参数是数据应发送到的进程的等级。第二个参数是用于识别数据的标签。第三个参数是数据。

标签始终是一个整数。在示例 47.2 中,标签是 16。标签可以识别对 send() 的调用。您会看到该标签与 recv() 一起使用。

传递给 send() 的第三个参数是 99。这个数字从等级 1 的进程发送到等级 0 的进程。Boost.MPI 支持所有原始类型。可以直接发送像 99 这样的 int 值。

recv() 需要类似的参数。第一个参数是应该从中接收数据的进程的等级。第二个参数是将对 recv() 的调用与对 send() 的调用链接起来的标签。第三个参数是存放接收到的数据的变量。

如果您使用至少两个进程运行示例 47.2,则会显示 99。

示例 47.3。从任何进程接收数据

#include <boost/mpi.hpp>
#include <iostream>
int main(int argc, char *argv[])
{
  boost::mpi::environment env{argc, argv};
  boost::mpi::communicator world;
  if (world.rank() == 0)
  {
    int i;
    world.recv(boost::mpi::any_source, 16, i);
    std::cout << i << '\n';
  }
  else
  {
    world.send(0, 16, world.rank());
  }
}

Example47.3

示例 47.3 基于示例 47.2。它不发送数字 99,而是发送调用 send() 的进程的等级。这可以是等级大于 0 的任何进程。

对等级为 0 的进程的 recv() 调用也发生了变化。 boost::mpi::any_source 是第一个参数。这意味着对 recv() 的调用将接受来自任何发送带有标签 16 的数据的进程的数据。

如果您使用两个进程启动示例 47.3,将显示 1。毕竟,只有一个进程可以调用 send()——rank 为 1 的进程。如果你启动程序时有两个以上的进程,不知道会显示哪个数字。在这种情况下,多个进程将调用 send() 并尝试发送它们的排名。哪个进程最先,因此显示哪个排名是随机的。

示例 47.4。使用 boost::mpi::status 检测发件人

#include <boost/mpi.hpp>
#include <iostream>
int main(int argc, char *argv[])
{
  boost::mpi::environment env{argc, argv};
  boost::mpi::communicator world;
  if (world.rank() == 0)
  {
    int i;
    boost::mpi::status s = world.recv(boost::mpi::any_source, 16, i);
    std::cout << s.source() << ": " << i << '\n';
  }
  else
  {
    world.send(0, 16, 99);
  }
}

recv() 的返回值类型为 boost::mpi::status。此类提供了一个成员函数 source(),它返回从中接收数据的进程的等级。示例 47.4 告诉您数字 99 是从哪个进程收到的。

到目前为止,所有示例都使用 send() 和 recv() 来传输 int 值。在示例 47.5 中,传输了一个字符串。

示例 47.5。使用 send() 和 recv() 传输数组

#include <boost/mpi.hpp>
#include <iostream>
int main(int argc, char *argv[])
{
  boost::mpi::environment env{argc, argv};
  boost::mpi::communicator world;
  if (world.rank() == 0)
  {
    char buffer[14];
    world.recv(boost::mpi::any_source, 16, buffer, 13);
    buffer[13] = '\0';
    std::cout << buffer << '\n';
  }
  else
  {
    const char *c = "Hello, world!";
    world.send(0, 16, c, 13);
  }
}

send() 和 recv() 可以传输数组和单个值。示例 47.5 传输字符数组中的字符串。因为 send() 和 recv() 支持像 char 这样的基本类型,所以可以毫无问题地传输 char 数组。

send() 将指向字符串的指针作为其第三个参数,并将字符串的大小作为其第四个参数。传递给 recv() 的第三个参数是指向存储接收数据的数组的指针。第四个参数告诉 recv() 应该接收多少个字符并将其存储在缓冲区中。示例 47.5 写出 Hello, world!到标准输出流。

示例 47.6。使用 send() 和 recv() 传输字符串

#include <boost/mpi.hpp>
#include <boost/serialization/string.hpp>
#include <string>
#include <iostream>
int main(int argc, char *argv[])
{
  boost::mpi::environment env{argc, argv};
  boost::mpi::communicator world;
  if (world.rank() == 0)
  {
    std::string s;
    world.recv(boost::mpi::any_source, 16, s);
    std::cout << s << '\n';
  }
  else
  {
    std::string s = "Hello, world!";
    world.send(0, 16, s);
  }
}

尽管 Boost.MPI 只支持原始类型,但这并不意味着它不能传输非原始类型的对象。 Boost.MPI 与 Boost.Serialization 一起工作。可以根据 Boost.Serialization 规则序列化的对象可以使用 Boost.MPI 进行传输。

示例 47.6 传输“Hello, world!”这次传输的值不是字符数组,而是 std::string。 Boost.Serialization 提供头文件 boost/serialization/string.hpp,只需要包含它以使 std::string 可序列化。

到此这篇关于C++ Boost MPI接口详细讲解的文章就介绍到这了,更多相关C++ Boost MPI内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++ Boost PointerContainer智能指针详解

    目录 一.提要 二.智能指针Boost.PointerContainer 三.练习 一.提要 在 C++11 中,Boost.PointerContainer是另一个智能指针,一般是用来生成集合数据的,本文阐述这种指针的特点和用法. 二.智能指针Boost.PointerContainer 库 Boost.PointerContainer 提供专门用于管理动态分配对象的容器.例如,在 C++11 中,您可以使用 std::vector<std::unique_ptr<int>> 创

  • C++ Boost ScopeExit超详细讲解

    目录 一.提要 二.退出作用域(Boost.ScopeExit) 2.1 范例1.UsingBOOST_SCOPE_EXIT 2.2 示例2.Boost.ScopeExit和C++11的lambda函数 2.3 示例3.特点BOOST_SCOPE_EXIT 三.练习 一.提要 资源有很多种,每种都封装一套,还是挺繁琐的!对于比较少使用或者一个程序很可能只会用一次的资源,我们不想封装,在这种情况下用Boost.ScopeExit. 二.退出作用域(Boost.ScopeExit) 库 Boost.

  • C++ Boost weak_ptr智能指针超详细讲解

    目录 一.提要 二.特别智能指针(Special Smart Pointers) 一.提要 在 C++11 中,boost::weak_ptr是另一类智能指针,一般是用COM组件生成.调用,本文阐述这种指针的特点和用法. 二.特别智能指针(Special Smart Pointers) 到目前为止介绍的每个智能指针都可以在不同的场景中单独使用.但是,boost::weak_ptr 仅在与 boost::shared_ptr 结合使用时才有意义. boost::weak_ptr 在 boost/w

  • C++ boost scoped_ptr智能指针详解

    目录 一.智能指针-唯一所有者 二.接口类分析 一.智能指针-唯一所有者 boost::scoped_ptr 是一个智能指针,它是动态分配对象的唯一所有者. boost::scoped_ptr 无法复制或移动.此智能指针在头文件 boost/scoped_ptr.hpp 中定义. 二.接口类分析 scoped_array 分析 scoped_array 的类部分原始代码如下: template<class T> class scoped_array // noncopyable { priva

  • C++ Boost Thread线程使用示例详解

    目录 一.并行编程 二.生成何管理Threads 练习 一.并行编程 以下库支持并行编程模型. Boost.Thread 允许您创建和管理自己的线程. Boost.Atomic 允许您通过多个线程的原子操作访问整数类型的变量. Boost.Lockfree 提供线程安全的容器. Boost.MPI 起源于超级计算机领域.使用 Boost.MPI,您的程序可以多次启动并在多个进程中执行.您专注于对应该并发执行的实际任务进行编程,而 Boost.MPI 会协调这些过程.使用 Boost.MPI,您无

  • C++ Boost Lambda表达式详解

    目录 lambda表达式格式 说明Boost.Lambda lambda表达式格式 lambda表达式的格式 [捕捉列表](参数列表)mutable->返回值类型{ 语句部分 }; 其中参数列表.返回值类型是可选的,捕捉列表.函数体可以为空. 先来看一个较为简单的lamda表达式 int main(void) { auto add = [](int a, int b)->int {return a + b; }; cout << add(1, 2) << endl; r

  • C++ Boost shared_ptr共享指针详细讲解

    目录 一.提要 二.智能指针boost::shared_ptr与boost::scoped_ptr 三.智能指针 boost::shared_ptr用法 示例1 示例2 示例3 示例4 示例5 一.提要 boost::shared_ptr是另一个智能指针,与 boost::scoped_ptr有很大不同,本文阐述这种区别. 二.智能指针boost::shared_ptr与boost::scoped_ptr 主要区别在于: boost::shared_ptr 不一定是对象的独占所有者. 所有权可以

  • C++ Boost MPI接口详细讲解

    目录 一.说明 二.开发和运行时环境 三.简单数据交换 一.说明 Boost.MPI 提供了 MPI 标准(消息传递接口)的接口.该标准简化了并发执行任务的程序的开发.您可以使用线程或通过共享内存或网络连接使多个进程相互通信来开发此类程序. MPI 的优点是你不需要关心这些细节.您可以完全专注于并行化您的程序. 缺点是您需要 MPI 运行时环境.如果您控制运行时环境,MPI 只是一个选项.例如,如果你想分发一个可以通过双击启动的程序,你将无法使用 MPI.虽然操作系统开箱即用地支持线程.共享内存

  • C++ Boost System超详细讲解

    目录 一.说明 二.关于 Boost.System库 一.说明 以下库支持错误处理. Boost.System 提供类来描述和识别错误.自 C++11 以来,这些类已成为标准库的一部分. Boost.Exception 使得在抛出异常后附加数据成为可能. 二.关于 Boost.System库 Boost.System Boost.System 是一个库,本质上定义了四个类来识别错误.所有四个类都已添加到 C++11 的标准库中.如果您的开发环境支持 C++11,则无需使用 Boost.Syste

  • C++ Boost Uuid超详细讲解

    目录 一.说明 二.Boost.Uuid库示例和代码 一.说明 Boost.Uuid 为 UUID 提供生成器. UUID 是不依赖于中央协调实例的通用唯一标识符.例如,没有数据库存储所有生成的 UUID,可以检查这些 UUID 是否使用了新的 UUID. UUID 由必须唯一标识组件的分布式系统使用.例如,Microsoft 使用 UUID 来识别 COM 世界中的接口.对于为 COM 开发的新接口,可以轻松分配唯一标识符. UUID 是 128 位数字.存在多种生成 UUID 的方法.例如,

  • C++ Boost Bimap示例详细讲解

    目录 一.提要 二.示例 练习 一.提要 库 Boost.Bimap 基于 Boost.MultiIndex 并提供了一个无需先定义即可立即使用的容器.该容器类似于 std::map,但支持从任一侧查找值. Boost.Bimap 允许您根据访问地图的方式创建任意一侧都可以作为关键点的地图.当您访问左侧作为键时,右侧是值,反之亦然. 二.示例 Example13.1.Usingboost::bimap #include <boost/bimap.hpp> #include <string

  • C++ Boost Tokenizer使用详细讲解

    目录 介绍 示例一 示例二 示例三 示例四 示例五 示例六 示例七 介绍 库 Boost.Tokenizer 允许您通过将某些字符解释为分隔符来迭代字符串中的部分表达式.使用 boost::tokenizer 迭代字符串中的部分表达式 示例一 使用 boost::tokenizer 迭代字符串中的部分表达式 #include <boost/tokenizer.hpp> #include <string> #include <iostream> int main() {

  • C++ Boost Lockfree超详细讲解使用方法

    目录 一.说明 二.示例和代码 Boost.Lockfree 一.说明 Boost.Lockfree 提供线程安全和无锁容器.可以从多个线程访问此库中的容器,而无需同步访问. 在 1.56.0 版本中,Boost.Lockfree 只提供了两个容器:boost::lockfree::queue 类型的队列和 boost::lockfree::stack 类型的栈.对于队列,可以使用第二个实现:boost::lockfree::spsc_queue.此类针对只有一个线程写入队列和只有一个线程从队列

  • C++ Boost Archive超详细讲解

    目录 一.说明 二.关于Archive库 一.说明 对Boost.Serialization库的应用,存在如下内容: Archive Pointers and References Serialization of Class Hierarchy Objects Wrapper Functions for Optimization Boost.Serialization 库可以将 C++ 程序中的对象转换为可以保存和加载以恢复对象的字节序列.有不同的数据格式可用于定义生成字节序列的规则. Boo

  • C++ Boost ProgramOptions超详细讲解

    目录 一.说明 二.示例Boost.ProgramOptions 一.说明 Boost.ProgramOptions Boost.ProgramOptions 是一个可以轻松解析命令行选项的库,例如,控制台应用程序.如果您使用图形用户界面开发应用程序,命令行选项通常并不重要. 要使用 Boost.ProgramOptions 解析命令行选项,需要以下三个步骤: 定义命令行选项.您给它们命名并指定哪些可以设置为一个值.如果命令行选项被解析为键/值对,您还可以设置值的类型——例如,它是字符串还是数字

  • C++ Boost Accumulators累加器详细讲解

    Boost.Accumulators Boost.Accumulators 提供了处理样本的类.例如,您可以找到最大或最小的样本,或者计算所有样本的总和.虽然标准库支持其中一些操作,但 Boost.Accumulators 还支持统计计算,例如均值和标准差. 该库称为 Boost.Accumulators,因为累加器是一个基本概念.累加器是一个容器,每次插入一个值时都会计算出一个新的结果.该值不一定存储在累加器中.相反,累加器在输入新值时不断更新中间结果. Boost.Accumulators

随机推荐