【问题标题】:How to make boost::serialization deserialization faster?如何使 boost::serialization 反序列化更快?
【发布时间】:2011-09-21 16:40:04
【问题描述】:

我使用 boost::serialization 来保存一个包含这些数据的对象:

struct Container
{
    struct SmallObject
    {
        struct CustomData
        {
            unsigned first;
            float second;
        };

        std::vector<CustomData> customData; // <- i can have 1 to 4 of these in the std::vector
        float data1[3];
        float data2[3];
        float data3[2];
        float data4[4];
    };

    std::vector<SmallObject> mySmallerObjects;  // <- i can have 8000 to 13000 of the std::vector
};

序列化代码是这样的(这在侵入式版本中,为了便于阅读,我没有写上面的函数声明):

template<class Archive> void Container::SmallObject::CustomData::serialize(Archive& ar, unsigned /*version*/)
{
    ar & first;
    ar & second;
}

template<class Archive> void Container::SmallObject::serialize(Archive& ar, unsigned /*version*/)
{
    ar & customData;
    ar & data1
    ar & data2;
    ar & data3;
    ar & data4;
}

template<class Archive> void Container::serialize(Archive& ar, unsigned /*version*/)
{
    ar & mySmallerObjects;
}

我使用 binary_archives。在发布模式下,加载我的容器(包含 12000 个小对象)大约需要 400 毫秒。有人告诉我这太长了。是否有任何设置或不同的内存布局可以加快加载过程?我应该放弃使用 boost::serialization 吗?

【问题讨论】:

  • 这 400 毫秒只是为了从磁盘读取对象吗?
  • @karlphillip 和 @ildjarn :我分别对从磁盘加载文件的部分(包括创建 boost 存档)和有效的反序列化部分(实际上只是语句“archive>>data;”进行了基准测试)。磁盘读取部分为几毫秒,有效反序列化为390毫秒。
  • 我们说的是多少字节?
  • @karlphillip : 1.07 MB(磁盘上 1,130,496 字节)
  • @wil :作为健全性检查,在反序列化之前,您究竟是如何从磁盘完全加载文件的?

标签: c++ performance serialization boost


【解决方案1】:

如果我必须选择 Boost.Serialization 的最大缺点,那就是性能不佳。如果 400 毫秒真的太慢,要么获得更快的硬件,要么切换到不同的序列化库。

也就是说,以防万一您做的事情明显“错误”,您应该发布ContainerContainer::SmallObjectContainer::SmallObject::CustomData 的序列化代码。您还应该确保它实际上是反序列化需要 400 毫秒,而不是反序列化 + 从磁盘读取数据的组合;即,将数据加载到某种内存流中并从中反序列化,而不是从 std::fstream 反序列化。


EDIT(回应 cmets):

此代码适用于我使用 VC++ 2010 SP1 和 Boost 1.47 beta:

double loadArchive(std::string const& archiveFileName, Container& data)
{
    std::ifstream fileStream(
        archiveFileName.c_str(),
        std::ios_base::binary | std::ios_base::in
    );
    std::stringstream buf(
        std::ios_base::binary | std::ios_base::in | std::ios_base::out
    );
    buf << fileStream.rdbuf();
    fileStream.close();

    StartCounter();
    boost::archive::binary_iarchive(buf) >> data;
    return GetCounter();
}

如果这对您不起作用,则它必须特定于您正在使用的编译器和/或 Boost 版本(是什么?)。

在我的机器上,对于 x86 版本构建(启用链接时代码生成),从磁盘加载数据大约是反序列化 1.28MB 文件(1 Container 包含 13000 @ 987654327@ 个实例,每个包含 4 个CustomData 实例);对于 x64 版本构建,从磁盘加载数据大约是反序列化 1.53MB 文件(相同的对象计数)所花费的总时间的 17%。

【讨论】:

  • 你是对的,实际上 400 ms 代表从磁盘读取数据(使用 std::ifstream)+ 反序列化的组合。我在最初的问题中添加了序列化代码。
  • @wil :接下来你需要做的是从内存而不是磁盘进行基准反序列化。如果它足够快,那么磁盘访问就是您的瓶颈,您对此无能为力...
  • 我可以毫无问题地编译和运行您的代码,但是发生了一件奇怪的事情,使用这种方法加载存档要慢得多(4500 毫秒)。
  • @wil :如果你没有发布完整的重现,我不确定要告诉你什么......我的示例文件的反序列​​化在我的机器上需要大约 140 毫秒。您使用的是哪个编译器和 Boost 版本,您是否 100% 肯定您正在对具有优化启用的构建进行基准测试?
【解决方案2】:

我建议将项目数写入序列化流,然后使用 std::vector::reserve 分配您需要的所有内存。这样,您将执行最少数量的分配。

【讨论】:

  • 除非他将每个 vector 的内容序列化为 C 数组(指针),而不是直接序列化 vector,Boost.Serialization 已经在内部完全按照您的建议进行。
猜你喜欢
  • 1970-01-01
  • 2011-05-15
  • 2013-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-18
  • 1970-01-01
  • 2014-11-11
相关资源
最近更新 更多