【问题标题】:Boost: Re-using/clearing text_iarchive for de-serializing data from Asio:receive()Boost:重用/清除 text_iarchive 以反序列化来自 Asio:receive() 的数据
【发布时间】:2015-04-08 08:26:56
【问题描述】:

这是我当前的函数,它对通过 Boost:Asio UDP 传输接收到的数据进行反序列化。它工作得很好,但是性能很差。每秒大约 4000 次左右的调用将使用约 16% 的 CPU,这是 I7 的完整线程。

对代码运行性能测试表明,这一行使用了 >95% 的 cpu 时间:

text_iarchive LLArchive(LLStream);

我的问题很简单:有没有一种方法可以重复使用 text_iarchive 而不必在每次调用函数时都创建一个新的? (在 C# 中也可以使用内存流和反序列化数据所需的其他变量)。我已经搜索了 Boost 文档,但没有提到任何类似的东西。

我本质上想要的是将下面的函数放在一个类中,并将尽可能多的变量定义为可以通过重新初始化(清除缓冲区/流,重新设置数据等)在函数内部使用的成员.这甚至会提高性能吗?更改传递到存档的流是否足以解决问题(它是否将其绑定到某个地方,以便如果我们更改传递的流,存档设置给自身的流也会更改)?

有可能吗?

非常感谢您的宝贵时间!

完整功能代码:

using namespace boost::archive;
using namespace boost::iostreams;

Packet InboundStreamToInternalPacket(boost::array<char, 5000> inboundStream)
{
    Packet receivedPacket; 

    basic_array_source<char> arraySourceLL(inboundStream.data(), inboundStream.size());
    stream<basic_array_source<char>> LLStream(arraySourceLL);
    text_iarchive LLArchive(LLStream);

    LLArchive >> receivedPacket;

    return receivedPacket;
}

编辑 1:

尝试再次关闭和打开流,就像添加了新源一样,在反序列化到第二个数据包时崩溃并出现“内存位置 xxxxxx 处的 boost::archive::archive_exception”。

Packet InboundStreamToInternalPacket(boost::array<char, 5000> inboundStream)
{
    Packet receivedPacket; 
    Packet receivedPacket2;

    basic_array_source<char> arraySourceLL(inboundStream.data(), inboundStream.size());
    stream<basic_array_source<char>> LLStream;     
    LLStream.open(arraySourceLL);

    text_iarchive LLArchive(LLStream);    

    LLArchive >> receivedPacket;

    LLStream.close();

    LLStream.open(arraySourceLL);

    LLArchive >> receivedPacket2;

    return receivedPacket;
}

【问题讨论】:

  • “这会提高性能吗?” - 你的分析器会告诉你。我打赌你听说过过早优化
  • 回复:编辑;你不能这样做,这是我在你编辑之前已经回答的。您需要存档实例。在答案中查看我的评论

标签: c++ serialization boost deserialization boost-asio


【解决方案1】:

不,没有这样的方法。

MemoryStream 的比较被打破了,因为存档是流的上方层。

可以重复使用该流。因此,如果您执行 MemoryStream 的精确并行,例如boost::iostreams::array_sink 和/或 boost::iostreams::array_source 在固定缓冲区上,您可以轻松地在下一次(反)序列化时重用缓冲区。

查看此概念证明:

Live On Coliru

#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/serialization.hpp>

#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>
#include <sstream>

namespace bar = boost::archive;
namespace bio = boost::iostreams;

struct Packet {
    int i;
    template <typename Ar> void serialize(Ar& ar, unsigned) { ar & i; }
};

namespace Reader {
    template <typename T>
    Packet deserialize(T const* data, size_t size) {
        static_assert(boost::is_pod<T>::value     , "T must be POD");
        static_assert(boost::is_integral<T>::value, "T must be integral");
        static_assert(sizeof(T) == sizeof(char)   , "T must be byte-sized");

        bio::stream<bio::array_source> stream(bio::array_source(data, size));
        bar::text_iarchive ia(stream);
        Packet result;
        ia >> result;

        return result;
    }

    template <typename T, size_t N>
    Packet deserialize(T (&arr)[N]) {
        return deserialize(arr, N);
    }

    template <typename T>
    Packet deserialize(std::vector<T> const& v) {
        return deserialize(v.data(), v.size());
    }

    template <typename T, size_t N>
    Packet deserialize(boost::array<T, N> const& a) {
        return deserialize(a.data(), a.size());
    }
}

template <typename MutableBuffer>
void serialize(Packet const& data, MutableBuffer& buf)
{
    bio::stream<bio::array_sink> s(buf.data(), buf.size());
    bar::text_oarchive ar(s);

    ar << data;
}

int main() {
    boost::array<char, 1024> arr;

    for (int i = 0; i < 100; ++i) {
        serialize(Packet { i }, arr);

        Packet roundtrip = Reader::deserialize(arr);
        assert(roundtrip.i == i);
    }
    std::cout << "Done\n";
}

对于 boost 序列化的一般优化,请参见:

【讨论】:

  • 所以我尝试通过关闭并再次打开它并传递 basic_array_source 来重新初始化流,但它不起作用。关闭后流为空,我似乎无法再次重新填充它
  • Edit2:所以从我所见,您已经对反序列化程序进行了模板化,并为传入的数据添加了一些断言检查。但是我可以看到该函数仍然定义了流和text_iarchive。如果我错了或对您的回答有其他期待,我很抱歉!您已经提到可以重用流,但据我所知,每次调用函数时仍会声明一个新流。
  • 你认为流是什么?除了一组指向缓冲区的指针(以及您不必使用的可选流状态,例如格式化选项/语言环境)之外?我认为建造成本并不高。而且,是的,您也可以重用流:see demo 但我假设您想重用对象为了性能,我很确定这不会由于涉及的分配,性能更好。随时纠正我的假设(最好通过更新问题措辞)
  • 这是 overwrites the same part of the stream each time 的演示。我不认为它会明显更快。在任何情况下,只要避免动态分配。使用二进制存档。禁用不需要的功能(版本控制、类型信息、标题)。益处。 (P.S.previous demo 不适用于二进制存档,AFAIR)
  • 我添加了更多链接。这是我分析了为什么在没有调整的情况下无法从单个流中反序列化 boost 二进制存档的答案:Outputting more things than a Polymorphic Text Archive
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-14
  • 2019-08-12
  • 2014-01-09
  • 1970-01-01
相关资源
最近更新 更多