在boost tutorial中有收集和减少操作的示例。收集代码如下:
#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;
}
还原的示例如下:
#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
}
我在这里无法理解的是if中的集体操作与其他中的什么不同?参数数量有所不同,但我不太明白逻辑是如何运作的。
由于
答案 0 :(得分:7)
MPI有两种类型的集体操作 - 具有指定的&#34; root&#34;过程和其他没有的过程。广播指定根的操作(根进程将相同的数据发送到所有进程),分散(根进程将其数据分散到所有进程),收集(根进程从所有进程收集数据)和减少(根进程从所有进程收集数据)同时减少它)。在MPI标准中,这些操作通常具有类似于以下的形式:
MPI_SCATTER(sendbuf, sendcount, sendtype,
recvbuf, recvcount, recvtype, root, comm)
此MPI调用具有输入和输出参数,必须在所有进程中使用,包括根目录,但输入参数(sendbuf
,sendcount
,sendtype
)仅在等级为root
且在所有其他过程中被忽略的过程中才有意义。
MPI是为便携性而设计的,因此MPI调用的设计使得它们可以在C和Fortran 77中以相同的方式实现 - 两种语言都不支持函数重载或MPI标准设计时的可选参数。 (不)幸运的是,像boost::mpi
这样的C ++库已经承担了C ++通过提供有效隐藏未使用的参数的那些调用的版本来提供重载功能的自由。现在很明显,对gather(world, my_number, 0)
的调用没有输出参数,因此有用于不是操作根的进程,而gather(world, my_number, all_numbers, 0)
有一个输出参数,因此只有才能在根目录中使用。这会在编写代码时产生一些不对称性 - 您必须执行if (world.rank() == root) { ... } else { ... }
。
我作为一个铁杆MPI用户认为这很丑,但还有其他人不同意我的看法。我猜......这取决于。
答案 1 :(得分:2)
看看:
升压/ MPI /集体/ gather.hpp
你会看到gather_impl的不同实现,一个在参数列表中有“out”值而另一个没有。没有“out”值的那个将其数据发送到根进程。所以在聚集示例中:
gather(world, my_number, 0)
实现mpi发送和
gather(world, my_number, all_numbers, 0)
为根处理器实现本地副本,为其他处理器实现mpi接收。