Google Protocol Buffers和ASN.1(使用PER编码)之间最明显的区别是什么?对于我的项目,最重要的问题是序列化数据的大小.有没有人在两者之间做过任何数据大小的比较?
如果使用带有未对齐PER的ASN.1,并使用适当的约束定义数据类型(例如,指定整数的上限/上限,列表长度的上限等),则编码将非常紧凑.对于诸如字段之间的对齐或填充之类的事物将不会浪费比特,并且每个字段将被编码为保持其允许的值范围所需的最小比特数.例如,INTEGER(1..8)类型的字段将以3位编码(1 ='000',2 ='001',...,8 ='111'); 具有四个备选方案的CHOICE将占用2位(表示所选择的备选方案)加上所选备选方案占用的位.ASN.1还有许多其他有趣的功能,已成功用于许多已发布的标准中.一个示例是扩展标记("..."),当应用于SEQUENCE,CHOICE,ENUMERATED和其他类型时,可以实现实现规范的不同版本的端点之间的向后兼容性.
自从我完成任何ASN.1工作以来已经很长时间了,但是这个大小很可能取决于你的类型和实际数据的细节.
我强烈建议您将两者都原型化并将一些真实数据放入比较中.
如果您的协议缓冲区包含重复的原始类型,您应该查看Subversion for Protocol Buffers中的最新源 - 它们现在可以以"压缩"格式表示,这样节省空间更多.(我的C#端口刚刚赶上了这个功能,上周某个时候.)
当打包/编码后的消息的大小很重要时,您还应该注意protobuf无法打包非repeated
字段的事实primitive numeric type
,请阅读以获取更多信息。
这是一个问题,例如,如果您有以下类型的消息:(注释定义了实际值范围)
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个字节。
原始数据Blob(假设z可以定义为int16
值)仅消耗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位高值)之间。