gpt4 book ai didi

c++ - 如何在 MPI_Send 中发送一个集合对象

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:35:43 27 4
gpt4 key购买 nike

我搜索发送一个 set 对象,我发现最接近的是 vector(它不同,不适用于 set)。

如何在 MPI_Send 中发送一个集合对象? (不使用 boost 库)任何人都可以举一个简单的例子吗?

最佳答案

在 MPI 中,无论是将复杂的数据结构写入文件还是通过网络,问题都是一样的;您必须将数据提取到“普通旧数据”(POD) 中,保存它,然后输出它,同样能够将保存的数据解压缩为相同类型的结构。通常,这称为序列化。

对于任何给定的结构,您始终可以编写自己的例程来执行此操作,但在 C++ 中,Boost 中有一个名为 Boost Serialization Library 的框架。为此;对于这个示例来说它有点重量级,但它适用于大多数(所有?)STL 容器,并且有用于添加对您自己的类的支持的 Hook 。

为此使用 Boost 的主要技巧是 Boost 库(以及所有示例)使将数据写入文件变得非常容易,但在这里您希望将其保存在内存中并通过网络;这意味着要跳过几个环节以确保序列化到一个您可以访问的数组中。 This SO answer在这方面很有帮助。

所以一个完整的工作示例如下所示:

#include <mpi.h>
#include <set>
#include <string>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/serialization/set.hpp>
#include <boost/iostreams/stream_buffer.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/device/back_inserter.hpp>

int main(int argc,char** argv) {

int size, rank;

MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);

if (size < 2) {
if (rank == 0)
std::cerr << "Require at least 2 tasks" << std::endl;
MPI_Abort(MPI_COMM_WORLD, 1);
}

const int lentag=0;
const int datatag=1;
if (rank == 0) {
int nums[] = {1,4,9,16};
std::set<int> send_set(nums, nums+4);

std::cout << "Rank " << rank << " sending set: ";
for (std::set<int>::iterator i=send_set.begin(); i!=send_set.end(); i++)
std::cout << *i << " ";
std::cout << std::endl;

// We're going to serialize into a std::string of bytes, and then send this
std::string serial_str;
boost::iostreams::back_insert_device<std::string> inserter(serial_str);
boost::iostreams::stream<boost::iostreams::back_insert_device<std::string> > s(inserter);
boost::archive::binary_oarchive send_ar(s);

send_ar << send_set;
s.flush();
int len = serial_str.size();

// Send length, then data
MPI_Send( &len, 1, MPI_INT, 1, lentag, MPI_COMM_WORLD );
MPI_Send( (void *)serial_str.data(), len, MPI_BYTE, 1, datatag, MPI_COMM_WORLD );
} else if (rank == 1) {
int len;
MPI_Recv( &len, 1, MPI_INT, 0, lentag, MPI_COMM_WORLD, MPI_STATUS_IGNORE);

char data[len+1];
MPI_Recv( data, len, MPI_BYTE, 0, datatag, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
data[len] = '\0';

boost::iostreams::basic_array_source<char> device(data, len);
boost::iostreams::stream<boost::iostreams::basic_array_source<char> > s(device);
boost::archive::binary_iarchive recv_ar(s);

std::set<int> recv_set;
recv_ar >> recv_set;

std::cout << "Rank " << rank << " got set: ";
for (std::set<int>::iterator i=recv_set.begin(); i!=recv_set.end(); i++)
std::cout << *i << " ";
std::cout << std::endl;
}

MPI_Finalize();
return 0;
}

运行给出:

$ mpic++ mpi-set.cxx -o mpiset -lboost_serialization
$ mpirun -np 2 ./mpiset
Rank 0 sending set: 1 4 9 16
Rank 1 got set: 1 4 9 16

如果您真的不想使用 Boost,因为您实际上无法直接查看集合数据结构,除了将数据提取到数组或 vector 中并以这种方式发送数据之外别无选择:

#include <mpi.h>
#include <set>
#include <vector>

int main(int argc,char** argv) {

int size, rank;

MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);

if (size < 2) {
if (rank == 0)
std::cerr << "Require at least 2 tasks" << std::endl;
MPI_Abort(MPI_COMM_WORLD, 1);
}

const int lentag=0;
const int datatag=1;
if (rank == 0) {
int nums[] = {1,4,9,16};
std::set<int> send_set(nums, nums+4);

std::cout << "Rank " << rank << " sending set: ";
for (std::set<int>::iterator i=send_set.begin(); i!=send_set.end(); i++)
std::cout << *i << " ";
std::cout << std::endl;

// Send length, then data
int len = send_set.size();
MPI_Send( &len, 1, MPI_INT, 1, lentag, MPI_COMM_WORLD );

std::vector<int> send_vec;
for (std::set<int>::iterator i=send_set.begin(); i!=send_set.end(); i++)
send_vec.push_back(*i);

MPI_Send( send_vec.data(), len, MPI_INT, 1, datatag, MPI_COMM_WORLD );

} else if (rank == 1) {

int len;
MPI_Recv( &len, 1, MPI_INT, 0, lentag, MPI_COMM_WORLD, MPI_STATUS_IGNORE);

int recv_data[len];
MPI_Recv( recv_data, len, MPI_INT, 0, datatag, MPI_COMM_WORLD, MPI_STATUS_IGNORE);

std::set<int> recv_set;
for (int i=0; i<len; i++)
recv_set.insert(recv_data[i]);

std::cout << "Rank " << rank << " got set: ";
for (std::set<int>::iterator i=recv_set.begin(); i!=recv_set.end(); i++)
std::cout << *i << " ";
std::cout << std::endl;
}

MPI_Finalize();
return 0;
}

运行得到:

$ mpicxx -o mpisetvector mpi-set-vector.cxx 
$ mpirun -np 2 mpisetvector
Rank 0 sending set: 1 4 9 16
Rank 1 got set: 1 4 9 16

但实际上,如果您还打算对其他类型的对象执行此操作,那么 Boost 是您的不二之选。

关于c++ - 如何在 MPI_Send 中发送一个集合对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31014044/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com