改进erlang版本的protobuf

protobuf是google开源的序列化工具,类似xml,json,基于二进制,比XML表示同样一段内容要短小得多,还可以定义一些可选字段,用于服务端与客户端通信。google没有提供对erlang语言的直接支持,所以这里使用到的第三方的protobuffs库,文章在这个库的基础上做一些改进。

在开始阅读这篇文章前,先了解一下原来erlang版的protobuf使用例子。改进版的protobuf代码及例子在这里(下载地址)。欢迎下载,有什么问题可以评论反馈。

改进protobuf

改进调用方法

原来调用比较别扭,每个协议都是不同的方法名:
encode() ->  
    Person = #person{age=25, name="John"},  
    test_pb:encode_person(Person).  
  
decode() ->  
    Data = encode(),  
    test_pb:decode_person(Data). 
现在改成了统一的方法名:
encode() ->  
    Person = #person{age=25, name="John"},  
    test_pb:encode(Person). %% 或者 test_pb:encode(person, Person)
  
decode() ->  
    Data = encode(),  
    test_pb:decode(person, Data). 
这样,很方便代码整合, 只要协议映射好,封包解包就可以统一在网关层处理。

改进空协议

message tos{
}
友好兼容空结构,原来空协议会报以下的警告信息
2> test_pb:encode_tos(#tos{}).
<<>>
3> c(test_pb).
src/test_pb.erl:33: Warning: variable 'Record' is unused
{ok,test_pb}

改进调用效率

改进了序列化和反序列化的效率,encode测试效率提升10 ~ 20%, decode测试效率提升10% ~ 40%
decode优化较大,实际有些情况不止40%,取均值,部分代码优化到协议编译期,所以调用就省事多了。

总结一些效率改进的技巧

获取record名字

[RecName | _] = tuple_to_list(Data)
改成了:
erlang:element(1,Data)

函数参数匹配优化

test(Bytes) when is_binary(Bytes) ->
    ok.
改成了
test(<<Bytes/binary>>) ->
    ok.
当匹配类型多时就会明显,guard模块对于多参数或多类型匹配尤为不利,erlang在编译期不能做优化。

分割二进制

Bytes = list_to_binary("0123456789"),
split_binary(Bytes, 3),

<<B1:3/binary, B2/binary>> = Bytes,%% 测试效率没erlang:split_binary/2高
{B1, B2}.

二进制合并

11> A= <<>>.
<<>>
12> B= <<"1333">>.
<<"1333">>
15> C= <<1,3,4>>.
<<1,3,4>>
16> iolist_to_binary([B,C,A]).
<<49,51,51,51,1,3,4>>
17> <<B/binary,C/binary,A/binary>>.
<<49,51,51,51,1,3,4>>
18> c(loop).
{ok,loop}
19> loop:test().
1000000 loops, using time: 281ms
1000000 loops, using time: 94ms

case匹配优化

case Data of
   {double, C} -> ok;
   {float, C} -> ok;
   {int, C} -> ok;
   {string, C} -> ok;
   _ -> ok
end

case Data of
   {C, double} -> ok;
   {C, float} -> ok;
   {C, int} -> ok;
   {C, string} -> ok;
   _ -> ok
end
第一种 匹配 效率较高,case匹配类似函数参数匹配,固定不变的内容放匹配表达式左边

比较erlang原生的二进制转换

最后,比较 erlang:term_to_binary/1 与 erlang:binary_to_term/1 的效率
测试结果发现erlang原生的二进制转换的效率超高,但是数据没压缩,不适合直接使用。实际使用需要配合 zlib:zip/1,这个是压缩工具,可能还需要稍微优化一下
zip(Data) ->
  Z = zlib:open(),
  Bs =
  try
      zlib:deflateInit(Z, best_speed, deflated, -15, 1, default),
      B = zlib:deflate(Z, Data, finish),
      zlib:deflateEnd(Z),
      B
  after
      zlib:close(Z)
  end,
  iolist_to_binary(Bs).
测试结果:
erlang:term_to_binary/1(配合zlib:zip/1)时间开销比 protobuf 多15%。
erlang:binary_to_term/1(配合zlib:unzip/1)时间开销差不多是 protobuf 的50%。


2015/6/11 修复字段默认值没有生效bug
2015/6/11 修复proto文件换行无法编译bug
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值