当前位置:  开发笔记 > 编程语言 > 正文

谷物和Boost序列化是否使用零拷贝?

如何解决《谷物和Boost序列化是否使用零拷贝?》经验,为你挑选了1个好方法。

我已经在几个序列化协议之间进行了一些性能比较,包括FlatBuffers,Cap'n Proto,Boost序列化和谷物.所有测试都是用C++编写的.

我知道FlatBuffers和Cap'n Proto使用零拷贝.使用零拷贝时,序列化时间为空,但序列化对象的大小更大.

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

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



1> Kenton Varda..:

在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(一种流行的非零拷贝序列化器)的作者.

推荐阅读
周扒pi
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有