Boost:Re-using/clearing text_iarchive 用于反序列化来自 Asio:receive() 的数据
Boost: Re-using/clearing text_iarchive for de-serializing data from Asio:receive()
这是我当前的函数,它对通过 Boost:Asio UDP 传输接收到的数据进行反序列化。它工作得很好,但是性能很差。每秒大约 4000 次左右的调用将使用 ~16% 的 CPU,这是一个 I7 的完整线程。
运行 对代码的性能测试表明该行使用了 >95% 的 cpu 时间:
text_iarchive LLArchive(LLStream);
我的问题很简单:有没有一种方法可以重复使用 text_iarchive 而不必在每次调用函数时都创建一个新的? (在 C# 中,使用内存流和反序列化数据所需的其他变量可能会发生类似的事情)。我搜索了 Boost 文档,但没有提到类似的内容。
我本质上想要的是将函数波纹管放在 class 中,并将尽可能多的变量定义为成员,这些成员将通过重新初始化(清除 buffer/stream、重新设置数据等)。这甚至会提高性能吗?更改传递到存档中的流是否足以达到目的(它是否将其绑定到某处,以便如果我们更改传递的流,存档设置为自身的流也会更改)?
可能吗?
非常感谢您的宝贵时间!
完整功能代码:
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:
尝试关闭并再次打开流,就好像添加了新源一样,在反序列化到第二个数据包时崩溃 "boost::archive::archive_exception at memory location xxxxxx"。
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
的比较被打破了,因为存档是 在 流之上的一层。
您可以重新使用流。因此,如果您执行与 MemoryStream 完全平行的操作,例如boost::iostreams::array_sink
and/or boost::iostreams::array_source
在固定缓冲区上,您可以轻松地在下一次(反)序列化中重用该缓冲区。
查看此概念证明:
#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";
}
对于提升序列化的一般优化,请参阅:
- how to do performance test using the boost library for a custom library
- Boost C++ Serialization overhead
- Boost Serialization Binary Archive giving incorrect output
- 调整事物(
boost::archive::no_codecvt
、boost::archive::no_header
、disable tracking 等)
- Outputting more things than a Polymorphic Text Archive and Streams Are Not Archives
这是我当前的函数,它对通过 Boost:Asio UDP 传输接收到的数据进行反序列化。它工作得很好,但是性能很差。每秒大约 4000 次左右的调用将使用 ~16% 的 CPU,这是一个 I7 的完整线程。
运行 对代码的性能测试表明该行使用了 >95% 的 cpu 时间:
text_iarchive LLArchive(LLStream);
我的问题很简单:有没有一种方法可以重复使用 text_iarchive 而不必在每次调用函数时都创建一个新的? (在 C# 中,使用内存流和反序列化数据所需的其他变量可能会发生类似的事情)。我搜索了 Boost 文档,但没有提到类似的内容。
我本质上想要的是将函数波纹管放在 class 中,并将尽可能多的变量定义为成员,这些成员将通过重新初始化(清除 buffer/stream、重新设置数据等)。这甚至会提高性能吗?更改传递到存档中的流是否足以达到目的(它是否将其绑定到某处,以便如果我们更改传递的流,存档设置为自身的流也会更改)?
可能吗?
非常感谢您的宝贵时间!
完整功能代码:
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:
尝试关闭并再次打开流,就好像添加了新源一样,在反序列化到第二个数据包时崩溃 "boost::archive::archive_exception at memory location xxxxxx"。
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
的比较被打破了,因为存档是 在 流之上的一层。
您可以重新使用流。因此,如果您执行与 MemoryStream 完全平行的操作,例如boost::iostreams::array_sink
and/or boost::iostreams::array_source
在固定缓冲区上,您可以轻松地在下一次(反)序列化中重用该缓冲区。
查看此概念证明:
#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";
}
对于提升序列化的一般优化,请参阅:
- how to do performance test using the boost library for a custom library
- Boost C++ Serialization overhead
- Boost Serialization Binary Archive giving incorrect output
- 调整事物(
boost::archive::no_codecvt
、boost::archive::no_header
、disable tracking 等) - Outputting more things than a Polymorphic Text Archive and Streams Are Not Archives