Fork me on GitHub
随笔 - 215  文章 - 13  trackbacks - 0
<2017年2月>
2930311234
567891011
12131415161718
19202122232425
2627281234
567891011


专注即时通讯及网游服务端编程
------------------------------------
Openresty 官方模块
Openresty 标准模块(Opm)
Openresty 三方模块
------------------------------------
本博收藏大部分文章为转载,并在文章开头给出了原文出处,如有再转,敬请保留相关信息,这是大家对原创作者劳动成果的自觉尊重!!如为您带来不便,请于本博下留言,谢谢配合。

常用链接

留言簿(1)

随笔分类

随笔档案

相册

Awesome

Blog

Book

GitHub

Link

搜索

  •  

积分与排名

  • 积分 - 211162
  • 排名 - 118

最新评论

阅读排行榜

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

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

改进protobuf

改进调用方法

原来调用比较别扭,每个协议都是不同的方法名:
[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. encode() ->    
  2.     Person = #person{age=25, name="John"},    
  3.     test_pb:encode_person(Person).    
  4.     
  5. decode() ->    
  6.     Data = encode(),    
  7.     test_pb:decode_person(Data).   
现在改成了统一的方法名:
[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. encode() ->    
  2.     Person = #person{age=25, name="John"},    
  3.     test_pb:encode(Person). %% 或者 test_pb:encode(person, Person)  
  4.     
  5. decode() ->    
  6.     Data = encode(),    
  7.     test_pb:decode(person, Data).   
这样,很方便代码整合,只要协议映射好,封包解包就可以统一在网关层处理。

改进空协议

[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. message tos{  
  2. }  
友好兼容空结构,原来空协议会报以下的警告信息
[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. 2> test_pb:encode_tos(#tos{}).  
  2. <<>>  
  3. 3> c(test_pb).  
  4. src/test_pb.erl:33: Warning: variable 'Record' is unused  
  5. {ok,test_pb}  

改进调用效率

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

总结一些效率改进的技巧

获取record名字

[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. [RecName | _] = tuple_to_list(Data)  
  2. 改成了:  
  3. erlang:element(1,Data)  

函数参数匹配优化

[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. test(Bytes) when is_binary(Bytes) ->  
  2.     ok.  
  3. 改成了  
  4. test(<<Bytes/binary>>) ->  
  5.     ok.  
当匹配类型多时就会明显,guard模块对于多参数或多类型匹配尤为不利,erlang在编译期不能做优化。

分割二进制

[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. Bytes = list_to_binary("0123456789"),  
  2. split_binary(Bytes, 3),  
  3.   
  4. <<B1:3/binary, B2/binary>> = Bytes,%% 测试效率没erlang:split_binary/2高  
  5. {B1, B2}.  

二进制合并

[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. 11> A= <<>>.  
  2. <<>>  
  3. 12> B= <<"1333">>.  
  4. <<"1333">>  
  5. 15> C= <<1,3,4>>.  
  6. <<1,3,4>>  
  7. 16> iolist_to_binary([B,C,A]).  
  8. <<49,51,51,51,1,3,4>>  
  9. 17> <<B/binary,C/binary,A/binary>>.  
  10. <<49,51,51,51,1,3,4>>  
  11. 18> c(loop).  
  12. {ok,loop}  
  13. 19> loop:test().  
  14. 1000000 loops, using time: 281ms  
  15. 1000000 loops, using time: 94ms  

case匹配优化

[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. case Data of  
  2.    {double, C} -> ok;  
  3.    {float, C} -> ok;  
  4.    {int, C} -> ok;  
  5.    {string, C} -> ok;  
  6.    _ -> ok  
  7. end  
  8.   
  9. case Data of  
  10.    {C, double} -> ok;  
  11.    {C, float} -> ok;  
  12.    {C, int} -> ok;  
  13.    {C, string} -> ok;  
  14.    _ -> ok  
  15. end  
第一种匹配效率较高,case匹配类似函数参数匹配,固定不变的内容放匹配表达式左边

比较erlang原生的二进制转换

最后,比较 erlang:term_to_binary/1 与 erlang:binary_to_term/1 的效率
测试结果发现erlang原生的二进制转换的效率超高,但是数据没压缩,不适合直接使用。实际使用需要配合 zlib:zip/1,这个是压缩工具,可能还需要稍微优化一下
[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. zip(Data) ->  
  2.   Z = zlib:open(),  
  3.   Bs =  
  4.   try  
  5.       zlib:deflateInit(Z, best_speed, deflated, -15, 1, default),  
  6.       B = zlib:deflate(Z, Data, finish),  
  7.       zlib:deflateEnd(Z),  
  8.       B  
  9.   after  
  10.       zlib:close(Z)  
  11.   end,  
  12.   iolist_to_binary(Bs).  
测试结果:
erlang:term_to_binary/1(配合zlib:zip/1)时间开销比 protobuf 多15%。
erlang:binary_to_term/1(配合zlib:unzip/1)时间开销差不多是 protobuf 的50%。

项目Git地址:
https://github.com/chenweiqi/erl_protobuffs/

2015/6/11 修复字段默认值没有生效bug
2015/6/11 修复proto文件换行无法编译bug
参考:http://blog.csdn.net/mycwq/article/details/42122439

附件下载erl_protobuffs.zip
posted on 2017-03-13 11:47 思月行云 阅读(1306) 评论(0)  编辑 收藏 引用 所属分类: Erlang

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理