ASN 和 PB 的编码效率比较

来源:互联网 发布:网络直播的营销手段 编辑:程序博客网 时间:2024/06/05 00:44
作者:王纯业
### 第一个例子
http://martin.kleppmann.com/2012/12/05/schema-evolution-in-avro-protocol-buffers-thrift.html 是一个很好的比较例子。
我类似的做了一个 ASN1 的结构
```
Person DEFINITIONS AUTOMATIC TAGS ::=
BEGIN
  Person ::= SEQUENCE {
    username PrintableString,
    favouritenumber INTEGER,
    interests SEQUENCE OF PrintableString
  }
END
```
用下面的方法编译
```
erlc -I. -bper Person.asn
erl
> c("Person").
{ok,'Person'}
> {ok, B} = 'Person':encode('Person', #'Person'{username = "Martin", favouritenumber = 1337, interests = ["daydreaming", "hacking"]}).
{ok,<<6,77,97,114,116,105,110,2,5,57,2,11,100,97,121,100,
      114,101,97,109,105,110,103,7,104,97,99,...>>}
> byte_size(B).
31
```
这个例子里面,ASN1 用了 31 bytes ,protobuf 用了 33 bytes, Avro 用了
32 bytes。 这不是一个公平的比较,对于大量使用小数据结构的时候,例如,
enum command type 之类的,ASN1 可以节省更多的 bytes 。
### 第二个例子
这是 protobuf 的定义。
```
package dummy;
message S {
  optional int32 a =1;
  optional bool b =2;
  optional int32 c =3;
  optional D   d =4;
}
message D {
  optional bool d1 = 1;
  optional bool d2 = 2;
}
```
用 erlang 编译 参考 [https://github.com/tomas-abrahamsson/gpb]()
```
> deps/gpb/bin/protoc-erl -I. -o-erl src -o-hrl include s1.proto
> erl -sname a@localhost
(a@localhost)1> R = #'S'{a=1,b=true,c=2, d=#'D'{d1 = true, d2 = true} }.
#'S'{a =1,b = true,c = 2,d = #'D'{d1 = true,d2 = true}}
(sync@localhost)2> s1:encode_msg(R).
<<8,1,16,1,24,2,34,4,8,1,16,1>>
(a@localhost)14> byte_size(s1:encode_msg(R)).
12
```
可以看到 protobuf 用了 12 个字节。
ASN1 的例子,使用  PER 编码方式。
```
Dummy DEFINITIONS AUTOMATIC TAGS ::=
BEGIN
  Dummy ::= SEQUENCE {
   a INTEGER (0..7),
   b BOOLEAN,
   c INTEGER (0..3),
   d SEQUENCE {
      d1 BOOLEAN,
      d2 BOOLEAN }}
END
```
```
> erlc -I. -bper Dummy.asn
> erl
(a@localhost)1> 'Dummy':encode('Dummy', #'Dummy'{ a = 1, b = true, c = 2, d = #'Dummy_d'{d1= true, d2 = true }}).
{ok,<<";">>}
```
protobuf 用了  12 个字节, ASN1 用了 1 个字节。同样,这也不是一个公平的比较。
很难做出公平的比较。但是可以说在大多数情况下 ASNPER 的编码是更加节省带宽的。
### 为什么 ASN1 PER 的编码效率比 PB 的高
1. ASN1 PER 是面向 bit 的编码方式,PB 是面向字节的编码方式。
2. PB 中 message 都是可以扩展的,ASN1 中只有使用  `...` 关键字的类型,才是可以扩展的。
3. PB 中的整数很简单,都是可以扩展到 64 位,ASN1 中有更加灵活(复杂) 的整数扩展方式。
2. PB 中的 `required`, `optional`, `oneof`, 和 `extensions` 的特性,对编码没有影响。例如,就算是 `required` 的字段,编码的时候,也是需要 tag 。
3. ASN1 PER 对很多关键字都是敏感的。例如
   1. `required` 的字段不会添加表明类型的 tag
   2. `required` 的字段按顺序编码。
4. tag 在 PER 中不做编码。
5. by default, every message is extensible in PB. Instread, ASN1 extensibility should be explicitly specified.
4. PB 中支持的整数类型不支持 subtype, 而 ASN1 PER 中的整数支持 subtype , 可以实现高效编码。
### 使用 ASN1 的优点
1. 编码紧凑,节省带宽。这是为什么几乎所有的 2G/3G/4G/5G 的无线通信协议都使用 ASN1 的原因之一。
2. ASN1 久经考验,asn1c 的项目已经十多年了,依然活跃开发。 Erlang 因为是通信公司创造的,语言内嵌 ASN 的支持。 Erlang 没有默认支持 PB 需要使用第三方开发库。
3. ASN1 支持 XER (XML) ,可以方便的调试。
4. wireshark 本身对 ASN1 的支持很好。
### 使用 ASN1 PER 的风险
1. ASN1 本身很复杂。ASN1 的学习成本高
2. PER 编码很复杂。可以用700行 C 代码实现 PB 的编解码,但实现 PER 编码不行。
3. ASN1 对语言的支持不多,似乎只有  C/Erlang 有比较好的使用。由于历史原因,通信领域几乎没有其他语言可供选择。
本文章版权归环信所有,转载请注明出处。更多技术文章请访问http://blog.easemob.com/
阅读全文
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 贺教授卫方被捕 教授分级如何划分 教授用英语怎么说 教授是什么级别 教授英语怎么说 教授英文单词 街球教授图片 卡斯迪诺夫教授 教研教改 教改 幼儿园教改论文 教改论文投稿 教改论文期刊 学校教改6人一组围着坐 教改论文哪些期刊好发 屡教不改 语文教材 教材 部编教材 教材帮 香港教材 英语教材 教材网 教材电子版 教材全解 教材教法 小学教材 大学教材 中国教材网 高数教材 培训教材 高一教材 教材书店 教材下载 四年级教材 学中文教材 教材解读 新概念教材 校本教材 教材购买 三年级教材