Google Protocol Buffers与ASN.1相比有何优劣之处?

47

谷歌协议缓冲区(Google Protocol Buffers)和ASN.1(具有PER编码)最显着的区别是什么?对于我的项目来说,最重要的问题是序列化数据的大小。是否有人在这两者之间进行过数据大小比较?


6
或许有一个相关的问题:既然已经有成熟的ASN.1,为什么我们还需要协议缓冲区呢?这是谷歌的“非此即彼”综合症吗? - coder.in.me
4个回答

25

如果你使用ASN.1和Unaligned PER,并使用适当的约束定义你的数据类型(例如,为整数指定下限/上限,在列表长度上指定上限等),那么你的编码将非常紧凑。不会浪费任何比特用于字段之间的对齐或填充,每个字段将使用最少量的位来表示其允许的值范围。例如,INTEGER类型的字段(1..8)将使用3位进行编码(1='000',2='001',...,8='111');而具有四种选择项的CHOICE将占用2位(指示所选选项)加上所选选项占用的位数。 ASN.1还具有许多其他有趣的功能,已成功地用于许多发布的标准中。例如,扩展标记(“...”),当应用于SEQUENCE、CHOICE、ENUMERATED和其他类型时,可以在实现不同版本规范的端点之间实现向前和向后兼容性。


13

我很久没做ASN.1相关的工作了,但是大小可能非常依赖于您类型和实际数据的细节。

极力建议您对两者进行原型设计,并放入一些真实数据来进行比较。

如果您的协议缓冲区包含重复的原始类型,您应该查看Protocol Buffers Subversion中的最新源代码 - 现在它们可以以更加空间高效的“打包”格式表示。(我的C#端口刚刚在上周实现了此功能。)


6
当压缩/编码消息的大小很重要时,您还应注意Protobuf无法压缩不是原始数字类型重复字段,有关更多信息,请阅读此处
例如,如果您具有以下类型的消息(注释定义实际值范围),这将是一个问题。
message P{
    required sint32 x = 1; // -0x1ffff  to  0x20000
    required sint32 y = 2; // -0x1ffff  to  0x20000
    required sint32 z = 3; // -0x319c  to   0x3200
}
message Array{
    repeated P ps = 1;
    optional uint32 somemoredata = 2;
}

如果你拥有一个长度为32的数组,那么在使用protobuf时,无论该数组包含哪些值,你都会得到一个大约250到450字节大小的紧凑消息。如果你使用了完整的32位范围或使用int32而不是sint32并且具有负值,则这个大小甚至可以增加到超过1000字节。
假设z可以定义为int16值的原始数据Blob只会消耗320字节,因此ASN.1消息始终小于320字节,因为最大值实际上不是32位而是19位(x,y)和15位(z)。
通过这条消息定义,可以优化protobuf消息大小:
message Ps{
    repeated sint32 xs = 1 [packed=true];
    repeated sint32 ys = 2 [packed=true];
    repeated sint32 zs = 3 [packed=true];
}
message Array{
    required Ps ps = 1;
    optional uint32 somemoredata = 2;
}

这会导致消息大小大约在100字节(所有值为零),300字节(范围最大值处的值)和500字节(所有值为高32位值)之间。


4

Protocol Buffers(协议缓冲区)不能保证二进制编码中字段的顺序,但是ASN.1可以。尽管在您的使用情况下可能并不容易注意到,但它是比较、数字签名、简化解析和可能其他应用程序的重要区别。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接