为什么varint是一种有效的数据表示?

时间:2014-07-07 15:43:55

标签: integer protocol-buffers data-representation

我目前正在研究protocol buffers的文档。 Varints描述为:

  

varint中的每个字节(最后一个字节除外)具有最重要的字节   bit(msb)set - 这表示还有其他字节。   每个字节的低7位用于存储二进制补码   以7位为单位表示数字,最不重要   小组第一。

我的问题是为什么人们会选择在每个字节上丢失一位的表示?这种方法有什么好处?

4 个答案:

答案 0 :(得分:13)

实际上,绝大多数整数值都很小。即使在您希望某个值有时会非常大的情况下,从而使其成为32位甚至64位,也可能通常很小,因为从统计上讲,大多数物理量都是如此遵循幂律分布。因此,如果较小的值可以存储在较少的字节中,那么如果较大的值需要额外的字节就可以了。

关于唯一没有受益的整数是哈希或随机生成的ID号,它们实际上并不代表数量,而只是一个字符串。对于这些,您应该使用Protobufs'fixed32fixed64类型。

请注意,varint编码节省了线路上的空间,但实际上相对较慢,因为它需要大量的分支来编码/解码。当然,它并不像文本编码那么慢,但作为二进制格式,它并不是那么好。这就是为什么Cap'n Proto决定撤销这个决定并在线上放置固定宽度的一个原因的原因之一。 Cap'n Proto还包括一个可选的“打包”算法,它压缩零值字节,产生与Protobuf类似的消息大小,但通常更快,因为算法使用较少的分支。

(披露:我是Cap'n Proto的作者,也是Google发布的大部分Protobuf代码。)

答案 1 :(得分:11)

节省空间/带宽,例如许多编程语言和协议都有固定大小的数据类型。例如uint8_t,uint16_t,uint32_t等等,无论值多大,这些都会占用固定的字节数。例如如果将值2存储在uint32_t中,则占用4个字节。

使用protobuf中使用的varint等编码,小值可以占用较小的空间,值2只需要在线上传输1个字节的空间,同时仍然足够灵活限制可以使用的值的范围。

如果小值比大值更常见,这通常是一个净胜利 - 通常就是这种情况。

答案 2 :(得分:3)

使用这种方法,如果你有很多小数字,你可以节省相当多的内存空间和/或传输时间,同时仍然能够代表任意大的数字。例如,您不必为每个数字分配8个字节。如果您有许多小数字,那么大多数这些字节都会为零。对于8字节数字,您的值限制为(2 ^ 64 - 1),如果您的值为2 ^ 64或更高,则需要执行一些特殊操作。

使用varint编码,通常可以节省大量内存,并且能够表示任意大小的数字。

答案 3 :(得分:2)

这是一个权衡,取决于您要发送的典型数字。

  • 如果它们通常很小,请使用“ varint”编码(int32, int64, uint32, uint64, sint32, sint64, bool, enum
  • 如果通常较大,请使用非“ varint”编码(fixed32, sfixed32, float, fixed64, sfixed64, double

这里是sint64int64fixed64用于各种数字的字节的比较:

[ RUN      ] ProtobufOutputStream.printNumberOfBytesOnWireForInts
                        number  sint64   int64 fixed64
                             0       2       2       9
                             1       2       2       9
                            -1       2      11       9
                            63       2       2       9
                           -63       2      11       9
                            64       3       2       9
                           -64       2      11       9
                         10000       4       3       9
                        -10000       4      11       9
           9223372036854775807      11      10       9
          -9223372036854775808      11      11       9