MPI收集/减少操作混乱

MPI gather/reduce operation confusion?

本文关键字:操作 混乱 收集 MPI      更新时间:2023-10-16

在boost教程中,有一些聚集和减少操作的示例。收集的代码如下:

#include <boost/mpi.hpp>
#include <iostream>
#include <vector>
#include <cstdlib>
namespace mpi = boost::mpi;
int main(int argc, char* argv[])
{
  mpi::environment env(argc, argv);
  mpi::communicator world;
  std::srand(time(0) + world.rank());
  int my_number = std::rand();
  if (world.rank() == 0) {
    std::vector<int> all_numbers;
    gather(world, my_number, all_numbers, 0);
    for (int proc = 0; proc < world.size(); ++proc)
      std::cout << "Process #" << proc << " thought of "
                << all_numbers[proc] << std::endl;
  } else {
    gather(world, my_number, 0);
  }
  return 0;
}

reduce的例子如下:

#include <boost/mpi.hpp>
#include <iostream>
#include <cstdlib>
namespace mpi = boost::mpi;
int main(int argc, char* argv[])
{
  mpi::environment env(argc, argv);
  mpi::communicator world;
  std::srand(time(0) + world.rank());
  int my_number = std::rand();
  if (world.rank() == 0) {
    int minimum;
    reduce(world, my_number, minimum, mpi::minimum<int>(), 0);
    std::cout << "The minimum value is " << minimum << std::endl;
  } else {
    reduce(world, my_number, mpi::minimum<int>(), 0);
  }
  return 0;
}

在这两个例子中,我们都有一个if/else条件,如下所示:

if(world.rank() == 0){
  //gather or reduce operation
  //Output
}else{
  //gather or reduce operation
}

我在这里不明白的是,如果中的集体操作和其他中的什么之间的区别?参数的数量有所不同,但我不太明白逻辑是如何实现的。

感谢

MPI有两种类型的集体操作——一种有指定的"根"进程,另一种没有。具有指定根的操作被广播(根进程向所有进程发送相同的数据)、分散(根进程将其数据分散到所有进程)、收集(根进程从所有进程收集数据)和减少(根进程收集所有进程的数据,同时对其应用减少)。在MPI标准中,这些操作的形式通常类似于:
MPI_SCATTER(sendbuf, sendcount, sendtype,
            recvbuf, recvcount, recvtype, root, comm)

此MPI调用同时具有输入和输出参数,必须在所有进程中使用,包括根进程,但输入参数(sendbufsendcountsendtype)仅在秩等于root的进程中有效,在所有其他进程中都被忽略。

MPI是为可移植性而设计的,因此MPI调用的设计使它们可以在C和Fortran 77中以相同的方式实现——在设计MPI标准时,这两种语言都不支持函数重载或可选参数。(Un-)幸运的是,像boost::mpi这样的C++库通过提供有效隐藏未使用参数的调用版本,获得了C++在重载函数时提供的自由。现在很明显,对gather(world, my_number, 0)的调用没有输出参数,因此它要在不是操作根的进程中使用,而gather(world, my_number, all_numbers, 0)有输出参数,所以只有才能在根中使用。这在编写代码时造成了一些不对称性——您必须执行if (world.rank() == root) { ... } else { ... }之类的操作。

作为MPI的铁杆用户,我认为这很丑陋,但也有其他人不同意我的观点。我想。。。这取决于情况。

查看:

boost/mpi/collectives/gather.hpp

您将看到gather_impl的不同实现,一个在参数列表中有"out"值,另一个没有。没有"out"值的进程将其数据发送到根进程。因此,在收集示例中:

gather(world, my_number, 0) 

实现mpi发送和

gather(world, my_number, all_numbers, 0) 

为根处理器实现本地拷贝,为其他处理器实现mpi接收。