38

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

4

4 回答 4

24

如果您将 ASN.1 与 Unaligned PER 一起使用,并使用适当的约束定义您的数据类型(例如,指定整数的下限/上限、列表长度的上限等),您的编码将非常紧凑。字段之间的对齐或填充之类的事情不会浪费任何位,并且每个字段将被编码为保持其允许的值范围所需的最小位数。例如,INTEGER (1..8) 类型的字段将被编码为 3 位(1='000', 2='001', ..., 8='111');一个有四个备选方案的 CHOICE 将占用 2 位(表示选择的备选方案)加上所选备选方案占用的位。ASN.1 有许多其他有趣的特性,已在许多已发布的标准中成功使用。一个例子是扩展标记(“...”),

于 2010-12-14T16:38:43.433 回答
13

我已经很久没有做过任何 ASN.1 工作了,但是大小很可能取决于您的类型和实际数据的详细信息。

强烈建议您将两者都制作原型并放入一些真实数据进行比较。

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

于 2009-02-27T15:49:04.273 回答
6

当打包/编码消息的大小很重要时,您还应该注意 protobuf 无法打包repeated不属于 a 的字段这一事实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 位值)之间。

于 2014-10-23T10:13:32.340 回答
3

Protocol Buffers 不保证二进制编码中字段顺序的保留,但 ASN.1 可以。它与大小无关,因此在您的用例中可能不是最明显的,但对于比较、数字签名、简化解析以及可能的其他应用程序来说,它是一个重要的区别。

于 2019-11-21T15:04:39.610 回答