C++ 谷物和Boost系列化是否使用零拷贝?

C++ 谷物和Boost系列化是否使用零拷贝?,c++,serialization,boost,copy,cereal,C++,Serialization,Boost,Copy,Cereal,我已经对几种序列化协议进行了性能比较,包括FlatBuffers、Cap'n Proto、Boost序列化和Groove。所有的测试都是用C++编写的。 我知道FlatBuffers和Cap'n Proto使用零拷贝。对于零拷贝,序列化时间为空,但序列化对象的大小更大 我以为谷类食品和Boost系列化没有使用零拷贝。但是,序列化时间(对于int和double)几乎为null,序列化对象的大小几乎与Cap'n Proto或Flatbuffers对象的大小相同。我在他们的文档中没有找到任何关于零拷贝

我已经对几种序列化协议进行了性能比较,包括FlatBuffers、Cap'n Proto、Boost序列化和Groove。所有的测试都是用C++编写的。 我知道FlatBuffers和Cap'n Proto使用零拷贝。对于零拷贝,序列化时间为空,但序列化对象的大小更大

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

谷物和Boost系列化也使用零拷贝吗

注:我给出了另一个更能理解问题全部范围的答案

Boost序列化是可扩展的

它允许您的类型描述需要序列化的内容,并允许归档描述格式

这可以是“零拷贝”-即,唯一的缓冲是在接收数据的流中(例如套接字或文件描述符)

有关动态位集序列化的有意识零拷贝实现的示例,请参见此答案中的代码:

我在网站上有很多这样的东西。还可以查看文档,了解它对容器序列化的影响(如果序列化连续分配的按位可序列化数据集合,结果是零拷贝,甚至是
\uu memcpy\u sse4
等)

旁注:Cap'nproto完全做了其他事情,AFAIK:它封送一些对象作为数据的未来。这显然是他们大肆宣传的内容。”∞% 更快,0µs!!!”(在从未检索到数据的情况下,这在某种程度上是正确的)


Boost和Score不执行Cap'n Proto或Flatbuffers意义上的零拷贝

使用真正的零拷贝序列化,live in memory对象的备份存储实际上与传递给
read()
write()
系统调用的内存段完全相同。根本没有包装/拆包步骤

一般来说,这有许多含义:

  • 不使用“新建/删除”分配对象。构造消息时,首先分配消息,这将为消息内容分配一个长的连续内存空间。然后直接在消息内部分配消息结构,接收实际上指向消息内存的指针。当消息稍后被写入时,一个
    write()
    调用会将整个内存空间推到电线上
  • 类似地,当您读入一条消息时,一个
    read()
    调用(或者2-3)会将整个消息读入一块内存中。然后获得指向消息“根”的指针(或类似指针的对象),您可以使用它来遍历消息。请注意,在应用程序遍历消息之前,不会实际检查消息的任何部分
  • 对于普通套接字,数据的唯一拷贝发生在内核空间中。使用RDMA网络,您甚至可以避免内核空间拷贝:数据直接从线路上传输到其最终内存位置
  • 使用文件(而不是网络)时,可以直接从磁盘
    mmap()
    发送非常大的消息,并直接使用映射的内存区域。这样做是O(1)——不管文件有多大。当您实际访问文件的必要部分时,操作系统将自动分页这些部分
  • 同一台机器上的两个进程可以通过共享内存段进行通信,而不需要拷贝。注意,一般来说,普通的C++对象在共享内存中不太好,因为内存段通常在两个内存空间中没有相同的地址,因此所有指针都是错误的。对于零拷贝序列化框架,指针通常表示为偏移量而不是绝对地址,因此它们是位置独立的
Boost和Score是不同的:当您在这些系统中收到消息时,首先会对整个消息执行一次传递,以“解包”内容。数据的最终存放位置是使用new/delete以传统方式分配的对象。类似地,在发送消息时,必须从对象树中收集数据,并将其打包到一个缓冲区中才能写出。尽管Boost和co谷是“可扩展的”,但真正的零拷贝需要一个非常不同的底层设计;不能将其作为延伸件栓接

也就是说,不要假设零拷贝总是更快
memcpy()
可以非常快,程序的其余部分可能会使成本相形见绌。同时,零拷贝系统往往有不方便的API,特别是由于内存分配的限制。总体而言,使用传统的序列化系统可能会更好地利用您的时间

零拷贝最明显的优势是在操作文件时,因为正如我提到的,您可以轻松地
mmap()
一个大文件,并且只读取其中的一部分。非零拷贝格式根本无法做到这一点。然而,当涉及到网络时,优势就不那么明显了,因为网络通信本身必然是O(n)

最后,如果您真的想知道哪种序列化系统对于您的用例来说最快,您可能需要全部尝试并测量它们。注意,玩具基准通常是误导性的;您需要测试您的实际用例(或非常类似的东西)以获得有用的信息


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

对不起,我很难理解boost序列化是如何实现零拷贝的。仅仅具有可扩展性是不够的:零拷贝需要一种完全不同的数据类型