简单介绍一下ProtoBuf的编码结构,然后通过一个简单的序列化示例熟悉ProtoBuf的大致编码过程,具体编码规则参考ProtoBuf官网:Protocol Buffers | Google Developershttps://developers.google.cn/protocol-buffers
注:其中的 Start group 和 End group 两种类型已被遗弃。
一个 message 编码将由一个个的 field 组成,每个 field 根据类型将有如下两种格式:
- Tag - Length - Value:编码类型表中 Type = 2 即 Length-delimited 编码类型将使用这种结构,
- Tag - Value:编码类型表中 Varint、64-bit、32-bit 使用这种结构。
Tag 由字段编号 field_number 和 编码类型 wire_type 组成,Tag 整体采用 Varints 编码,wire_type可用的类型如下:
Varints 编码:在每个字节开头的 bit 设置了 msb(most significant bit ),标识是否需要继续读取下一个字节,存储数字对应的二进制补码,补码的低位排在前面,类似小端模式。
ZigZag 编码:有符号整数映射到无符号整数,然后再使用 Varints 编码,sint32、sint64 将采用 ZigZag 编码(编码结构依然为 Tag - Value)。
Varints 编码,我们可以发现 Varints 的本质实际上是每个字节都牺牲一个 bit 位(msb),来表示是否已经结束(是否还需要读取下一个字节),msb 实际上就起到了 Length 的作用,正因为有了 msb(Length),所以我们可以摆脱原来那种无论数字大小都必须分配四个字节的窘境。通过 Varints 我们可以让小的数字用更少的字节表示。从而提高了空间利用和效率。
这里为什么强调牺牲?因为每个字节都拿出一个 bit 做 msb,而原先这个 bit 是可直接用来表示 Value 的,现在每个字节都少了一个 bit 位即只有 7 位能真正用来表达 Value。那就意味这 4 个字节能表达的最大数字为 228,而不再是 232 了。
这意味着什么?意味着当数字大于 228 时,采用 Varints 编码将导致分配 5 个字节,而原先明明只需要 4 个字节,此时 Varints 编码的效率不仅不是提高反而是下降。
但这并不影响 Varints 在实际应用时的高效,因为事实证明,在大多数情况下,小于 228 的数字比大于 228 的数字出现的更为频繁。
下面是一些参考
protobuf 数据解析的2种方法 - 拥剑公子 - 博客园深入 ProtoBuf - 编码 - 简书在对 ProtoBuf 做了一些基本介绍之后,这篇开始进入正题,深入 ProtoBuf 的一些原理,让我们看看 ProtoBuf 是如何尽其所能的压榨编码性能和效率的。 编码...https://www.jianshu.com/p/73c9ed3a4877