C++集体数据交换实现示例讲解

作者:无水先生 时间:2023-12-17 11:35:07 

一、说明

到目前为止介绍的功能共享一对一的关系:即一个进程发送和一个进程接收。链接是通过标签建立的。本节介绍在多个进程中调用相同参数但执行不同操作的函数。对于一个进程,函数可能会发送数据,对于另一个进程,它可能会接收数据。这些功能称为集体操作。

二、示例和代码

示例 47.9。使用 gather() 从多个进程接收数据

#include <boost/mpi.hpp>
#include <boost/serialization/string.hpp>
#include <vector>
#include <string>
#include <iterator>
#include <algorithm>
#include <iostream>
int main(int argc, char *argv[])
{
 boost::mpi::environment env{argc, argv};
 boost::mpi::communicator world;
 if (world.rank() == 0)
 {
   std::vector<std::string> v;
   boost::mpi::gather<std::string>(world, "", v, 0);
   std::ostream_iterator<std::string> out{std::cout, "\n"};
   std::copy(v.begin(), v.end(), out);
 }
 else if (world.rank() == 1)
 {
   boost::mpi::gather(world, std::string{"Hello, world!"}, 0);
 }
 else if (world.rank() == 2)
 {
   boost::mpi::gather(world, std::string{"Hello, moon!"}, 0);
 }
}

Example47.9

示例 47.9 在多个进程中调用函数 boost::mpi::gather()。函数是发送还是接收取决于参数。

等级为 1 和 2 的进程使用 boost::mpi::gather() 发送数据。它们将发送的数据作为参数传递&mdash;&mdash;字符串&ldquo;Hello, world!&rdquo;和&ldquo;你好,月亮!&rdquo; &ndash; 以及数据应传输到的进程的级别。由于 boost::mpi::gather() 不是成员函数,因此还必须传递 communicator world。

等级为 0 的进程调用 boost::mpi::gather() 来接收数据。由于数据必须存储在某个地方,因此传递了一个 std::vector<std::string> 类型的对象。请注意,您必须将此类型与 boost::mpi::gather() 一起使用。不支持其他容器或字符串类型。

排名 0 的进程必须传递与排名 1 和 2 的进程相同的参数。这就是排名 0 的进程也传递 world、要发送的字符串和 0 到 boost::mpi::gather() 的原因。

如果您使用三个进程启动示例 47.9,您好,世界!和你好,月亮!被显示。如果仔细查看输出,您会注意到首先写入了一个空行。第一行是等级为 0 的进程传递给 boost::mpi::gather() 的空字符串。 v 中有三个字符串,它们是从等级为 0、1 和 2 的进程接收的。向量中元素的索引对应于进程的等级。如果多次运行该示例,您将始终得到一个空字符串作为向量中的第一个元素,&ldquo;Hello, world!&rdquo;作为第二个元素和&ldquo;你好,月亮!&rdquo;作为第三个。

请注意,您不得使用超过三个进程运行示例 47.9。例如,如果您使用 -n 4 启动 mpiexec,则不会显示任何数据。该程序将挂起,必须使用 CTRL+C 中止。

必须对所有进程执行集体操作。如果您的程序调用诸如 boost::mpi::gather() 之类的函数,您必须确保该函数在所有进程中都被调用。否则就违反了 MPI 标准。因为像 boost::mpi::gather() 这样的函数必须被所有进程调用,所以每个进程的调用通常没有不同,如示例 47.9 所示。将前面的示例与执行相同操作的示例 47.10 进行比较。

示例 47.10。使用 gather() 从所有进程收集数据

#include <boost/mpi.hpp>
#include <boost/serialization/string.hpp>
#include <vector>
#include <string>
#include <iterator>
#include <algorithm>
#include <iostream>
int main(int argc, char *argv[])
{
 boost::mpi::environment env{argc, argv};
 boost::mpi::communicator world;
 std::string s;
 if (world.rank() == 1)
   s = "Hello, world!";
 else if (world.rank() == 2)
   s = "Hello, moon!";
 std::vector<std::string> v;
 boost::mpi::gather(world, s, v, 0);
 std::ostream_iterator<std::string> out{std::cout, "\n"};
 std::copy(v.begin(), v.end(), out);
}

您为所有流程中的集体操作调用函数。通常函数的定义方式很清楚必须执行哪个操作,即使所有进程都传递相同的参数。

示例 47.10 使用 boost::mpi::gather() 来收集数据。数据在其等级作为最后一个参数传递给 boost::mpi::gather() 的过程中收集。此进程收集它从所有进程接收的数据。存储数据的向量仅供收集数据的进程使用。

boost::mpi::gather() 从所有进程收集数据。这包括收集数据的过程。在示例 47.10 中,这是等级为 0 的进程。该进程在 s 中向自身发送一个空字符串。空字符串存储在 v 中。正如您将在以下示例中看到的,集合操作始终包括所有进程。

您可以使用任意数量的进程运行示例 47.10,因为每个进程都会调用 boost::mpi::gather()。如果您使用三个进程运行该示例,结果将与前面的示例类似。

示例 47.11。在所有进程中使用 scatter() 分散数据

#include <boost/mpi.hpp>
#include <boost/serialization/string.hpp>
#include <vector>
#include <string>
#include <iostream>
int main(int argc, char *argv[])
{
 boost::mpi::environment env{argc, argv};
 boost::mpi::communicator world;
 std::vector<std::string> v{"Hello, world!", "Hello, moon!",
   "Hello, sun!"};
 std::string s;
 boost::mpi::scatter(world, v, s, 0);
 std::cout << world.rank() << ": " << s << '\n';
}

Example47.11

示例 47.11 介绍了函数 boost::mpi::scatter()。它与 boost::mpi::gather() 相反。 boost::mpi::gather() 将来自多个进程的数据收集到一个进程中,而 boost::mpi::scatter() 将来自一个进程的数据分散到多个进程中。

示例 47.11 将来自排名为 0 的进程的 v 中的数据分散到所有进程,包括它自己。等级为 0 的进程接收到字符串&ldquo;Hello, world!&rdquo;在 s 中,排名为 1 的进程收到&ldquo;你好,月亮!&rdquo;在 s 中,等级为 2 的进程收到&ldquo;Hello, sun!&rdquo;秒。

示例 47.12。使用 broadcast() 向所有进程发送数据

#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;
 std::string s;
 if (world.rank() == 0)
   s = "Hello, world!";
 boost::mpi::broadcast(world, s, 0);
 std::cout << s << '\n';
}

boost::mpi::broadcast() 将数据从一个进程发送到所有进程。此函数与 boost::mpi::scatter() 之间的区别在于将相同的数据发送到所有进程。在示例 47.12 中,所有进程都收到字符串&ldquo;Hello, world!&rdquo;在 s 中写下你好,世界!到标准输出流。

示例 47.13。使用 reduce() 收集和分析数据

#include <boost/mpi.hpp>
#include <boost/serialization/string.hpp>
#include <string>
#include <iostream>
std::string min(const std::string &lhs, const std::string &rhs)
{
 return lhs.size() < rhs.size() ? lhs : rhs;
}
int main(int argc, char *argv[])
{
 boost::mpi::environment env{argc, argv};
 boost::mpi::communicator world;
 std::string s;
 if (world.rank() == 0)
   s = "Hello, world!";
 else if (world.rank() == 1)
   s = "Hello, moon!";
 else if (world.rank() == 2)
   s = "Hello, sun!";
 std::string result;
 boost::mpi::reduce(world, s, result, min, 0);
 if (world.rank() == 0)
   std::cout << result << '\n';
}

boost::mpi::reduce() 从多个进程收集数据,如 boost::mpi::gather()。但是,数据不存储在向量中。 boost::mpi::reduce() 需要一个函数或函数对象,它将用于分析数据。

如果您使用三个进程运行示例 47.13,则排名为 0 的进程会收到字符串&ldquo;Hello, sun!&rdquo;结果。对 boost::mpi::reduce() 的调用收集并分析所有进程传递给它的字符串。它们使用函数 min() 进行分析,该函数作为第四个参数传递给 boost::mpi::reduce()。 min() 比较两个字符串并返回较短的一个。

如果您使用三个以上的进程运行示例 47.13,则会显示一个空字符串,因为排名大于 2 的所有进程都会将一个空字符串传递给 boost::mpi::reduce()。将显示空字符串,因为它比&ldquo;Hello, sun!&rdquo;短

示例 47.14。使用 all_reduce() 收集和分析数据

#include <boost/mpi.hpp>
#include <boost/serialization/string.hpp>
#include <string>
#include <iostream>
std::string min(const std::string &lhs, const std::string &rhs)
{
 return lhs.size() < rhs.size() ? lhs : rhs;
}
int main(int argc, char *argv[])
{
 boost::mpi::environment env{argc, argv};
 boost::mpi::communicator world;
 std::string s;
 if (world.rank() == 0)
   s = "Hello, world!";
 else if (world.rank() == 1)
   s = "Hello, moon!";
 else if (world.rank() == 2)
   s = "Hello, sun!";
 std::string result;
 boost::mpi::all_reduce(world, s, result, min);
 std::cout << world.rank() << ": " << result << '\n';
}

Example47.14

示例 47.14 使用函数 boost::mpi::all_reduce(),它像 boost::mpi::reduce() 一样收集和分析数据。这两个函数之间的区别在于 boost::mpi::all_reduce() 将分析结果发送到所有进程,而 boost::mpi::reduce() 使结果仅可用于排名作为传递的进程最后一个参数。因此,没有排名传递给 boost::mpi::all_reduce()。如果您使用三个进程运行示例 47.14,每个进程都会写入 Hello, sun!到标准输出流。

来源:https://yamagota.blog.csdn.net/article/details/127941993

标签:C++,集体,数据交换
0
投稿

猜你喜欢

  • C#使用DoddleReport快速生成报表

    2022-05-31 06:39:59
  • C# CheckedListBox控件的用法总结

    2023-09-17 13:23:34
  • Android 使用maven publish插件发布产物(aar)流程实践

    2023-03-04 18:07:45
  • C#条件语句、循环语句(if、while)

    2023-09-27 19:49:23
  • springboot vue前后端接口测试树结点添加功能

    2022-05-22 18:51:09
  • 浅谈C#中的for循环与foreach循环

    2021-08-23 03:27:38
  • Java循环队列原理与用法详解

    2023-11-13 20:05:36
  • Java高级特性之反射机制实例详解

    2023-10-08 06:33:51
  • C#调用和实现WebService,纯手工打造!

    2023-12-12 14:58:30
  • 浅谈Java工程读取resources中资源文件路径的问题

    2021-07-20 19:13:45
  • GridView基于pulltorefresh实现下拉刷新 上拉加载更多功能(推荐)

    2022-08-29 23:51:58
  • C#不提升自己程序的权限实现操作注册表

    2023-01-24 18:51:31
  • Android使用SoundPool播放短音效

    2022-03-02 12:33:00
  • C#控制台实现飞行棋游戏

    2022-03-12 04:18:40
  • java匿名内部类实例简析

    2022-12-26 21:25:15
  • android canvas使用line画半圆

    2022-01-05 17:58:57
  • 简单实现Android倒计时效果

    2022-03-26 01:58:14
  • 快速了解如何在.NETCORE中使用Generic-Host建立主机

    2022-05-08 15:04:12
  • SpringBoot AOP使用笔记

    2023-12-09 13:25:50
  • C#中通过反射将枚举元素加载到ComboBo的实现方法

    2022-05-26 09:28:10
  • asp之家 软件编程 m.aspxhome.com