简体   繁体   English

如何在MPI_Send中发送设置对象

[英]How to send a set object in MPI_Send

I searched to send a set object and the closest I found was with vector (it's different and don't work with set). 我搜索发送一个设置对象,我找到的最接近的是矢量(它是不同的,不适用于set)。

How can I send a set object in MPI_Send? 如何在MPI_Send中发送设置对象? (without using boost library) Anyone can put a simple example? (不使用boost库)任何人都可以举一个简单的例子?

Whether you have to write a complex data structure to a file or over the network in MPI, the issues are the same; 无论您是要在MPI中将复杂数据结构写入文件还是通过网络,问题都是一样的; you have to extract the data into "Plain Old Data" (POD), save it, and then output it, and likewise be able to unpack the saved data into the same sort of structure. 您必须将数据提取到“普通旧数据”(POD),保存,然后输出,同样能够将保存的数据解压缩到相同类型的结构中。 In general, this is called serialization. 通常,这称为序列化。

For any given structure you can always write your own routines for doing this, but in C++, there's a framework in Boost called the Boost Serialization Library for doing this; 对于任何给定的结构,您总是可以编写自己的例程来执行此操作,但在C ++中,Boost中有一个框架,称为Boost序列化库,用于执行此操作; it's a bit heavyweight for this example but it will work for most (all?) STL containers and there are hooks for adding support for your own classes. 对于这个例子来说它有点重量级,但它适用于大多数(所有?)STL容器,并且有一些钩子可以为你自己的类添加支持。

The main trick with using Boost for this is that the Boost libraries (and all the examples) make it very easy to write the data to a file, but here you want to keep it in memory and send/receive it over the network; 使用Boost的主要技巧是Boost库(以及所有示例)使得将数据写入文件变得非常容易,但是在这里你要将它保存在内存中并通过网络发送/接收它; that means jumping through a couple more hoops to make sure the serialization is into an array you can access. 这意味着跳过更多的箍,以确保序列化进入您可以访问的数组。 This SO answer is very helpful in this regard. 在这方面,这个答案非常有用。

So a complete working example looks like this: 所以一个完整的工作示例如下所示:

#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;
}

Running gives: 跑步给出:

$ 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

If you really don't want to use Boost, since you can't actually see directly into the set data structure, there's not much alternative but to extract the data into an array or vector, and send the data that way: 如果你真的不想使用Boost,因为你实际上无法直接看到set数据结构,除了将数据提取到数组或向量中之外没有太多选择,并以这种方式发送数据:

#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;
}

And running gives: 跑步给出:

$ 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 

But really, if you're going to be doing this with other types of object as well, Boost is the way to go. 但实际上,如果你打算用其他类型的对象做这件事,那么Boost就是你要走的路。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM