Google协议缓冲区与ASN.1相比如何?

问题描述:

Google协议缓冲区和ASN.1(使用PER编码)最显着的区别是什么?对于我的项目来说,最重要的问题是序列化数据的大小。有没有人在两者之间做过任何数据大小的比较?Google协议缓冲区与ASN.1相比如何?

+0

也许是一个相关的问题:当我们已经有一个成熟的ASN.1时,为什么我们需要协议缓冲区? Google没有在这里发明综合征? – 2018-03-05 09:58:50

自从我完成了任何ASN.1工作以来,这已经很长时间了,但其大小很可能取决于您的类型和实际数据的细节。

我会强烈建议您原型,并把一些真实的数据进行比较。

如果您的协议缓冲区包含重复的原始类型,您应该查看Subversion协议缓冲区中的最新源代码 - 它们可以用现在更加节省空间的“打包”格式表示。 (我的C#端口有只是赶上了这个功能,上周一些时间。)

如果使用ASN.1与非对齐PER,并确定使用相应的约束(数据类型例如,指定下/上整数的范围,列表长度的上限等),您的编码将非常紧凑。对于字段之间的对齐或填充等内容,将不会浪费比特,并且每个字段都将被编码为保持其允许的值范围所需的最小比特数。例如,INTEGER(1..8)类型的字段将被编码为3位(1 ='000',2 ='001',...,8 ='111');而一个有四种选择的CHOICE将占用2位(表示所选择的选择)加上所选备选项占用的位。 ASN.1还有许多其他有趣的功能,已经在许多已发布的标准中成功使用。一个例子是扩展标记(“...”),当它应用于SEQUENCE,CHOICE,ENUMERATED和其他类型时,实现了实现不同版本规范的端点之间的向前和向后兼容性。

当打包/编码消息的大小是很重要的,你也应该注意一个事实,即protobuf的无法收拾repeated字段是一个primitive numeric type的不是,read this以获取更多信息。

这是一个问题,例如如果有该类型的消息:(评论定义值的实际范围)

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比你会导致大约250到450个字节的填充消息大小与protobuf,取决于数组实际包含的值。如果您使用int32而不是sint32并且具有负值,那么在使用完整32位范围的情况下,这甚至可以增加到超过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位值)。