2017-06-06 58 views
0

我试图通过MPI与不同大小的std::vector<MyClass>进行通信。 MyClass包含可能未初始化或大小不同的矢量的成员。为此,我写了一个serialize()deserialize()函数,读写这样的std::vector<MyClass>std::string,然后我通过MPI进行通信。使用MPI将对象的向量序列化为std :: string

class MyClass { 
    ... 
    int some_int_member; 
    std::vector<float> some_vector_member; 
} 

std::vector<MyClass> deserialize(const std::string &in) { 
    std::istringstream iss(in); 

    size_t total_size; 
    iss.read(reinterpret_cast<char *>(&total_size), sizeof(total_size)); 

    std::vector<MyClass> out_vec; 
    out_vec.resize(total_size); 

    for(MyClass &d: out_vec) { 
     size_t v_size; 
     iss.read(reinterpret_cast<char *>(&d.some_int_member), sizeof(d.some_int_member)); 
     iss.read(reinterpret_cast<char *>(&v_size), sizeof(v_size)); 
     d.some_vector_member.resize(v_size); 
     iss.read(reinterpret_cast<char *>(&d.some_vector_member[0]), v_size * sizeof(float)); 
    } 

    return out_vec; 
} 


std::string serialize(std::vector<MyClass> &data) { 
    std::ostringstream os; 

    size_t total_size = data.size(); 
    os.write(reinterpret_cast<char *>(&total_size), sizeof(total_size)); 

    for(MyClass &d: data) { 
     size_t v_size = d.some_vector_member.size(); 
     os.write(reinterpret_cast<char *>(&some_int_member), sizeof(some_int_member)); 
     os.write(reinterpret_cast<char *>(&v_size), sizeof(v_size)); 
     os.write(reinterpret_cast<char *>(&d.some_vector_member[0]), v_size * sizeof(float)); 
    } 
    return os.str(); 
} 

我工作的实施原则,但有时(并不总是!)MPI在我认为都与系列化位置进程崩溃。发送的有效载荷可以和MB的胡言乱语一样大。我怀疑使用std::string作为容器不是一个好的选择。使用std::string作为char[]的容器时是否存在一些限制,我可能会在这里使用巨大的二进制数据?

(请注意,我不希望使用boost::mpi以其系列化程序一起,我也不希望在一个巨大的图书馆拉如cereal到我的项目)

+0

我不确定你想从答案中得到什么。这是关于崩溃?然后我们需要一个[mcve]和你目前调试工作的描述。或者这是关于如何正确地进行序列化?或者,这是如何发送复合C++对象与MPI(序列化只是一个答案)?如果这实际上是关于“*通过MPI *实现发送序列化数据”,那么至少我们需要查看您的MPI代码。这些问题中的许多问题也很重视意见(“*更好的方法*”),请将重点放在特定目标和标准上。 – Zulan

+0

嗨祖兰,对不起,这个问题不是很精确。我会尝试重述它。我在大型数值模拟中使用上述例程,即使许多MPI请求没有问题,也会有时会崩溃。堆栈跟踪不是很有帮助(它包含'bad_alloc',所以我猜它是一些内存事物),并且我不能轻松创建一个最小工作示例。我怀疑'std :: string'的一些限制是问题,因此我的问题。 – janoliver

+0

你可以尝试将你的serialize方法封装在try {...} catch(std :: bad_alloc&){...}块中。此外,您可以使用内存分析器来分析内存泄漏。 –

回答

1

通常,使用std::string二进制数据虽然有些人可能更喜欢std::vector<char> - 或std::vector<std::byte> C++ 17(see also,请注意C++ 11字符串保证连续的数据)。代码中有两个重要的效率问题:

  1. 您总是有三份全部数据。原始对象,序列化的string和中间的[io]stringstream
  2. 您不能预先分配(保留)ostringstream中的数据,这可能会导致过度分配和频繁的重新分配。

因此,你浪费了大量的内存,这可能有助于bad_alloc。也就是说,它可能非常好,你只是在某处存在内存泄漏。在不知道bad_alloc的原因以及应用程序的性能分析的情况下,无法判断这是否是实际问题。