Boost:重复使用/清除text_iarchive以从Asio:receive()反序列化数据 [英] Boost: Re-using/clearing text_iarchive for de-serializing data from Asio:receive()

查看:134
本文介绍了Boost:重复使用/清除text_iarchive以从Asio:receive()反序列化数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我当前的功能,用于反序列化通过Boost:Asio UDP传输接收的数据.它运行得很好,但是性能却很差.每秒大约4000次左右的调用将占用约16%的CPU,这是I7的全线程.

This is my current function that de-serializes data received via Boost:Asio UDP transmission. It works perfectly, however the performance is pretty bad. About 4000 or so calls per second will use ~16% of CPU, which is a full thread of an I7.

对代码进行性能测试表明,此行使用了超过95%的cpu时间:

Running a performance test on the code shows that this line uses >95% of the cpu time:

text_iarchive LLArchive(LLStream);

我的问题很简单:是否有一种方法可以重用text_iarchive,而不必每次调用该函数时都创建一个新的? (在C#中,使用内存流和其他反序列化数据所需的变量,可能会发生类似的事情).我搜索了Boost文档,却没有提及任何类似的东西.

My question is simple: is there a way I can re-use a text_iarchive without having to create a new one each time the function is called? (a similar thing is possible in C# with memorystreams and other variables needed to deserialise data). I've searched through the Boost documentation and no mention was made of anything like it.

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

What I essentially want is to put the function bellow in a class and have as many variables as possible defined as members that would simply be used inside the function through re-initialization (clearing buffer/stream, re-setting data etc). Will this even improve the performance? Would changing the stream passed into the archive be enough to do the trick (does it bind it somewhere so that if we change the passed stream, the one the archive sets to itself changes as well) ?

有可能吗?

非常感谢您的光临!

全功能代码:

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

尝试像重新添加流一样再次关闭和打开流,在反序列化到第二个Packet时,崩溃并显示为"boost :: archive :: archive_exception在内存位置xxxxxx".

Tried closing and opening the stream again as if a new source was added, crashes with "boost::archive::archive_exception at memory location xxxxxx" when de-serializing into the second Packet.

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

推荐答案

没有这种方法.

MemoryStream的比较虽然无效,因为存档位于流的上方层.

The comparison to MemoryStream is broken though, because the archive is a layer above the stream.

可以重新使用流.因此,如果您执行与MemoryStream完全相同的并行操作,例如boost::iostreams::array_sink和/或boost::iostreams::array_source在固定缓冲区上,则可以在下一个(反)序列化中轻松重用该缓冲区.

You can re-use the stream. So if you do the exact parallel of a MemoryStream, e.g. boost::iostreams::array_sink and/or boost::iostreams::array_source on a fixed buffer, you can easily reuse the buffer in you next (de)serialization.

请参阅此概念证明:

在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序列化的一般优化,请参见:

For general optimization of boost serialization see:

  • how to do performance test using the boost library for a custom library
  • Boost C++ Serialization overhead
  • Boost Serialization Binary Archive giving incorrect output
  • Tune things (boost::archive::no_codecvt, boost::archive::no_header, disable tracking etc.)
  • Outputting more things than a Polymorphic Text Archive and Streams Are Not Archives

这篇关于Boost:重复使用/清除text_iarchive以从Asio:receive()反序列化数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆