协议缓冲区和 Avro 中的 ZigZag 编码背后的原因是啥?
Posted
技术标签:
【中文标题】协议缓冲区和 Avro 中的 ZigZag 编码背后的原因是啥?【英文标题】:What's the reason behind ZigZag encoding in Protocol Buffers and Avro?协议缓冲区和 Avro 中的 ZigZag 编码背后的原因是什么? 【发布时间】:2016-02-29 08:24:24 【问题描述】:ZigZag 需要大量开销来写入/读取数字。实际上,我惊讶地发现它不仅按原样写入 int/long 值,而且还进行了许多额外的加扰。甚至涉及到一个循环: https://github.com/mardambey/mypipe/blob/master/avro/lang/java/avro/src/main/java/org/apache/avro/io/DirectBinaryEncoder.java#L90
我似乎无法在 Protocol Buffers 文档或 Avro 文档中找到,或者我自己推理,这样的加扰数字有什么好处?为什么编码后正负数交替比较好?
为什么它们不只是以小端、大端、网络顺序编写的,只需要将它们读入内存并可能反转位字节序?我们用性能买什么?
【问题讨论】:
如果您对类似 protobuf 且不进行昂贵的 varint 编码的东西感兴趣,请参阅 capnproto.org。它更快,但它确实需要更多的电线空间。 (披露:我是 Cap'n Proto 的作者,也是 Google 大部分开源 Protobuf 代码的作者。) @KentonVarda 感谢您提供的信息,我不知道 Cap'n'proto。添加到我的协议工具带中。 协议缓冲区,至少从版本 2 开始,如果这对您的应用程序更有意义,让您使用固定大小的编码整数(例如 -fixed32、sfixed64 等)。例如,如果您的值将均匀分布在可能的值范围内,那么您希望使用固定形式而不是可变形式。话虽如此,常用值的聚类接近于零是很常见的,这种简单的可变长度编码可以节省大量空间。 【参考方案1】:这是一个可变长度的 7 位编码。编码值的第一个字节将其高位设置为 0,随后的字节将其设置为 1。这是解码器可以判断用于编码值的字节数的方式。无论机器架构如何,字节顺序始终是小端序。
这是一种编码技巧,允许写入所需的尽可能少的字节来对值进行编码。因此,一个 8 字节的 long 值介于 -64 和 63 之间,只占用一个字节。这很常见,long 提供的范围在实践中很少使用。
在没有 gzip 风格压缩方法开销的情况下紧密打包数据是设计目标。也用于.NET Framework。对值进行编码/解码所需的处理器开销是无关紧要的。它已经比压缩方案低很多,只是 I/O 成本的一小部分。
【讨论】:
非常感谢。我真的很感谢你的帮助。现在它完全有道理。我迷路了,因为我开始查看unnecessarily obfuscated in some places 的Java 源代码。天哪,Java 真的需要手工制作的循环展开代码才能快速运行吗? @Endrju:低级库协议的性能要求非常高,因为此类库的用户差异很大。库代码具有非常多样化的客户端集合,其中一些具有严格的性能要求。此外,库代码有成为瓶颈的趋势,因此优化库通常至关重要。选择库时,性能通常是首要考虑因素。 可能,但在针对嵌入式系统时可能不是。乐观地说,希望有人实际测试过代码并验证它提供了好处。实际上,它可能被验证为既正确又足够性能,然后被忽略了。除非他们出于其他原因已经在处理它,否则熟练的专业人员通常不愿修改符合性能和正确性目标的工作代码。您也许可以分析更改历史,以找出该循环展开的原因;也许它是为了响应基准而完成的? 这个答案的第二句话是错误的。每个八位字节的最高有效位被保留以指示编码是否继续。例外情况是第 9 个八位字节,其中所有 8 位代表值的一部分。 一个经常丢失的快速注释——通常传输/传输一个字节所需的时间大大超过了奇怪编码所需的处理时间。即使在 1Gb/s 线速下,运行在 2+ GHz 的现代处理器也将通过在简单编码而不是传输上花费周期来“获胜”。在 IoT 和 BLE 等环境中,带宽非常有限,而处理器的性能相对更高,因此奇怪的编码是一个巨大的胜利。以上是关于协议缓冲区和 Avro 中的 ZigZag 编码背后的原因是啥?的主要内容,如果未能解决你的问题,请参考以下文章