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

时间:2009-02-27 15:43:33

标签: performance serialization protocol-buffers asn.1

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

4 个答案:

答案 0 :(得分:21)

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

答案 1 :(得分:8)

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

强烈建议您将两者都原型化并将一些真实数据放入比较中。

如果您的协议缓冲区包含重复的原始类型,您应该查看Subversion for Protocol Buffers中的最新源 - 它们现在可以以“压缩”格式表示,这样节省空间更多。 (我的C#端口只是赶上了这个功能,上周某个时候。)

答案 2 :(得分:4)

当打包/编码邮件的大小很重要时,您还应注意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)比使用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位值)之间。

答案 3 :(得分:0)

协议缓冲区不能保证以二进制编码形式保留字段顺序,但是ASN.1可以。它与大小无关,因此在您的用例中可能不是最引人注目,但对于比较,数字签名,简化的解析以及其他应用程序而言,这是一个重要的区别。