首頁 > 軟體

C++集體資料交換實現範例講解

2022-11-21 14:00:59

一、說明

到目前為止介紹的功能共用一對一的關係:即一個程序傳送和一個程序接收。連結是通過標籤建立的。本節介紹在多個程序中呼叫相同引數但執行不同操作的函數。對於一個程序,函數可能會傳送資料,對於另一個程序,它可能會接收資料。這些功能稱為集體操作。

二、範例和程式碼

範例 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() 傳送資料。它們將傳送的資料作為引數傳遞——字串“Hello, world!”和“你好,月亮!” – 以及資料應傳輸到的程序的級別。由於 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 的程序接收的。向量中元素的索引對應於程序的等級。如果多次執行該範例,您將始終得到一個空字串作為向量中的第一個元素,“Hello, world!”作為第二個元素和“你好,月亮!”作為第三個。

請注意,您不得使用超過三個程序執行範例 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 的程序接收到字串“Hello, world!”在 s 中,排名為 1 的程序收到“你好,月亮!”在 s 中,等級為 2 的程序收到“Hello, sun!”秒。

範例 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 中,所有程序都收到字串“Hello, world!”在 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 的程序會收到字串“Hello, sun!”結果。對 boost::mpi::reduce() 的呼叫收集並分析所有程序傳遞給它的字串。它們使用函數 min() 進行分析,該函數作為第四個引數傳遞給 boost::mpi::reduce()。 min() 比較兩個字串並返回較短的一個。

如果您使用三個以上的程序執行範例 47.13,則會顯示一個空字串,因為排名大於 2 的所有程序都會將一個空字串傳遞給 boost::mpi::reduce()。將顯示空字串,因為它比“Hello, sun!”短

範例 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!到標準輸出流。

到此這篇關於C++集體資料交換實現範例講解的文章就介紹到這了,更多相關C++集體資料交換內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com