c++ - Cereal 和Boost序列化是否使用零拷贝?

标签 c++ serialization boost copy cereal

我在几种序列化协议(protocol)之间做了一些性能比较,包括FlatBuffers,Cap'n Proto,Boost序列化和谷类。所有测试都是用C++编写的。

我知道FlatBuffers和Cap'n Proto使用零复制。对于零复制,序列化时间为空,但序列化对象的大小较大。

我以为 Cereal 和Boost序列化不使用零拷贝。但是,序列化时间(对于int和double)几乎为空,并且序列化对象的大小几乎与Cap'n Proto或Flatbuffers的大小相同。我没有在他们的文档中找到有关零复制的任何信息。

Cereal 和Boost序列化也使用零拷贝吗?

最佳答案

在Cap'n Proto或Flatbuffers的意义上,Boost和Cereal会执行而不是来实现零复制。

通过真正的零副本序列化,活内存中对象的后备存储实际上与传递给read()write()系统调用的内存段完全相同。根本没有包装/拆箱步骤。

通常,这具有许多含义:

  • 不使用new/delete分配对象。构造消息时,首先分配消息,这将为消息内容分配一个长的连续内存空间。然后,您直接在消息内部分配消息结构,接收实际上指向消息内存的指针。以后写消息时,一个write()调用会将整个内存空间推到线路上。
  • 同样,当您读入一条消息时,一个read()调用(或者可能是2-3个)将整个消息读入一个内存块中。然后,您将获得一个指向消息“根”的指针(或类似指针的对象),可用于遍历消息。请注意,在您的应用程序遍历该消息之前,不会真正检查该消息的任何部分。
  • 使用普通套接字,数据的唯一副本位于内核空间中。借助RDMA网络,您甚至可以避免内核空间复制:数据直接从有线传输到其最终存储位置。
  • 处理文件(而不是网络)时,可以直接从磁盘上对很大的消息进行mmap(),并直接使用映射的内存区域。这样做是O(1)-文件的大小无关紧要。实际访问它们时,操作系统将自动分页文件的必要部分。
  • 同一台计算机上的两个进程可以通过没有副本的共享内存段进行通信。请注意,通常,常规的旧C++对象在共享内存中不能很好地工作,因为内存段通常在两个内存空间中的地址都不相同,因此所有指针都是错误的。在零拷贝序列化框架中,指针通常表示为偏移量而不是绝对地址,因此它们与位置无关。

  • Boost和Cereal是不同的:当您在这些系统中收到消息时,首先对整个消息执行传递以“解包”内容。数据的最终存放位置是使用new/delete以传统方式分配的对象。类似地,在发送消息时,必须从该对象树中收集数据并将其打包到一个缓冲区中才能被写出。即使Boost和Cereal是“可扩展的”,但要实现真正的零复制就需要非常不同的底层设计。它不能作为扩展插入。

    就是说,不要以为零复制总是会更快。 memcpy()可能很快,而程序的其余部分可能会使成本相形见.。同时,零拷贝系统倾向于具有不方便的API,特别是由于内存分配的限制。总的来说,使用传统的序列化系统可能会更好地利用您的时间。

    零复制最明显的优势是在处理文件时,因为正如我提到的那样,您可以轻松地对大文件进行mmap(),而只读取其中的一部分。非零拷贝格式根本无法做到这一点。但是,在联网方面,优势并不十分明显,因为网络通信本身必定为O(n)。

    归根结底,如果您真的想知道哪种序列化系统最适合您的用例,则可能需要全部尝试并进行评估。请注意,玩具基准测试通常会产生误导;您需要测试您的实际用例(或非常类似的用例)以获得有用的信息。

    披露:我是Cap'n Proto(零拷贝序列化程序)和Protocol Buffers v2(流行的非零拷贝序列化程序)的作者。

    关于c++ - Cereal 和Boost序列化是否使用零拷贝?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41801826/

    相关文章:

    c# - Windows Mobile 中的 Flash SMS

    c++ - 使用输入和输出运算符读取用户定义类型的对象

    c# - 在 Linux 上反序列化 TimeZoneInfo 会抛出 `The Month parameter must be in the range 1 through 12`

    java - @XmlElementWrapper 序列化无法使用 Jackson JaxB 注释工作

    c++ - 在 jam 文件中指定 Boost.build 内置功能

    c++ - 将 std::vector 序列化为 Boost 二进制存档时出现数据相关故障

    c++ - 将 boost::chrono::steady_clock::time_point 转换为 std::chrono::steady_clock::time_point

    c++ - 在类中使用 tostring。 C++

    c++ - 在线判断编程,如spoj,topcoder

    java - 单个文件中多个java对象的序列化和反序列化