[Erlang_Question21]Binary为什么可以节省大量的空间?

第一次看到Joe Armstong的《Erlang 程序设计》里面对Binary的描述时,觉得这个东西好复杂,语法这么奇特(我觉得是Erlang语法中最不好懂的部分);

然后在项目中:Binary的处理都在网络包处理层,基本不会有改动,所以从此以后就再也没有去深看Binary。

但是看cowboy最新版本的优化说:

https://github.com/ninenines/cowboy

Cowboy aims to provide a complete HTTP stack in a small code base. It is optimized for low latency and low memory usage, in part because it uses binary strings.


就又非(gu)常(qi)好(yong)奇(qi)地想了解下这个神奇的Binary.[可是网络上的关于Binary的资料真的是少得可怜...]

但是:不过还是淘到了几篇非常好的文章:

  1. ErlangVM 是怎么实现Binary数据类型的,实现原理从宏观到细节,值得反复细读:http://www.cnblogs.com/zhengsyao/p/erlang_eterm_implementation_5_binary.html
  2. 这个是从应用层上去具体使用上去解释为什么Binary会非常高效且内存占用比List少:http://cryolite.iteye.com/blog/1547252
  3. 1 中提到的官方效率指南:http://www.erlang.org/doc/efficiency_guide/binaryhandling.html
  4. 如果要处理Binary最好自己写模式匹配或使用binary.erl里面的函数:http://stackoverflow.com/questions/21779394/erlang-high-memory-usage-for-processing-list-of-binary-parts

理解了上面的内容后,就会认识到Binary的强大,但是对Binary的语法还是心存恐惧:

其实如果一个事物不熟悉或太自由,大部分人都首先觉得“哇,好牛逼”,渐渐地恰恰由于这过多的自由(太灵活),有时会感觉到自身的驾驭能力不足,多少会有点害怕,进而就不想去理解它【抱着一种反正可以用其它方法取代的心态】

下面,我们就通过把Binary和List(这个不熟悉就说不过去了)对比来看Binary的语法,不要因为恐惧错过美好的东西:


引用: http://user.it.uu.se/~pergu/papers/erlang05.pdf

首先我们知道List的语法是最简单,明了的。其实Binary的目的最终也是想把Binary的语法和List保持一致

1.Binary怎么节省的空间?

 keep_0XX([{0,B2,B3}|Rest]) ->
    [{0,B2,B3}|keep_0XX(Rest)];
 keep_0XX([{1,_,_}|Rest]) ->
    keep_0XX(Rest);
 keep_0XX([]) ->
    [].

或者使用下面的列表解析方式:

keep_0XX(List) ->
  [{0,B2,B3} || {0,B2,B3} <- List].

上面这个函数看上去简洁优雅,简直可以说是完美,但是还有2个问题:

1.1 这个三元tuple非常浪费空间,如果使用<<B1/Size1,B2/Size2,B3/Size2>>来从bit级别去理解你的需要,想分配多少就直接给多个,这样才是极致;

1.2 输入的不确定性:可能来自于网络,或能来自于文件中,这时,我们还要把得到的数据转化为一个3元tuple的List,为什么不能一步到位?

所以:这里使用Binary[网络中的数据包大部分都是Binary,除了文本的http]会更好:

keep_0XX(Bin) ->
    [ <<0:1,B:2>> || <<0:1,B:2>> <= Bin].

2.Binary语法:温故而知新,多想想它为什么要这么规定[一切都是为了网络数据]?

<<Segment1,Segment2,...,Senmentn>>

每个Segment都是现面这种方式

Value:Size/TypeSpecifierList

2.1.Value可以是任意的Erlang Term,绑定的变量,不绑定的变量,不关心的"_";

2.2 Size 可以是正整数或绑定为正整数的变量(不能是不绑定变量),但总的Size加起来一定是8的倍数,因为二进制没有办法表达一个非8倍数长度的比特串;

Integer默认为8,Float默认为64,其它类型在模式匹配时必须指定Size.

2.3 TypeSpecifierList 由End-Sign-Type-Unit的列表:每一个前置项可以忽略,没有要求。

2.3.1 Type可以是: integer | float | binary | bytes | bitstring | bits | utf8 | utf16 | utf32 如果不指定就默认为Integer

2.3.2 Signedness: signed | unsigned 只有当Type为Integer时才会有用,默认为‘unsigned‘

2.3.3 Endianness: big | little | native 指定计算机系统的字节序,native是运行时决定的字节序,依赖于CPU,默认为big,唯一用到这项的情形就是处理整数和二进制数据之间的封包和解包工作。

例如你在big上看到的是<<0,0,0,72>> 在little上看到的是<<72,0,0,0>>.

2.3.4 Unit: unit:Integer 1~255 整个区块长度为Size*Unit bit整个区块的长度必须>=0且 整除8

Unit默认值由Type决定:Type=integer或float时为1,Type=binary则为8

Joe大爷说:如果你还是对比特语法感觉不适应,最好的办法就是在shell中尝试你需要的模式直接得到真确的值,然后把它们复制粘贴到程序中就行啦。他就是这么做的....

给一些binary默认时的情况给你测试下下:

Segment Default expansion
X X:8/integer-unit:1
X/float X:64/float-unit:1
X/binary X:all/binary
X:size/binary X:Size/binary-unit:8

3.Binary模式匹配

3.1 示例1:最基本的:

Binary = <<10, 11, 12>>,
   <<A:8, B/binary>> = Binary.
   A=10,B=<<11,12>>.

3.2 示例2 Size并不需要事先绑定值,通常的做法是:

<<Sz:8/integer,
Vsn:Sz/integer,
Msg/binary>> = <<16,2,154,42>>.
Sz = 16,Vsn=666,Msg=<<42>>.

先从前面得到头,再在后面的匹配中使用

3.3.

case Binary of
<<42:8/integer, X/binary>> ->
   handle bin(X);
<<Sz:8, V:Sz/integer, X/binary>> when Sz > 16 ->
   handle int bin(V, X);
<< :8, X:16/integer, Y:8/integer>> ->
  handle int int(X, Y)
end.
Binary Matching of X
<<42,14,15>> <<14,15>>
<<24,1,2,3,10,20>> <<10,20>>
<<12,1,2,20>> 258
<<0,255>> failure

4.一些关于binary的BIF

4.1 binary_to_list(Bin)  这个函数只能处理size为8的整数的Bin[你可以试下:binary_to_list(<<1:21>>)).];

4.2 size(Bin)是返回存储Bin实际的大小空间,不是分配给他的,如果你要查看分配给他的,就用bit_size(Bin).

5.Binary 的binary解析【相对于List的列表解析】

不要忘记了Binary的语法的终极目标,做得和List一样好用!

5.1 把Binary转换为List:【只需要<-变成了<= 】

1> [ X || <<X>> <= <<1,2,3,4,5>>, X rem 2 == 0].
    [2,4]

 5.2 如果你只是想把不是binary处理后变成一个binary就不用使用 <=

2> << <<R:8, G:8, B:8>> ||  {R,G,B} <- [{213,45,132},{64,76,32},{76,0,0},{234,32,15}] >>.
  <<213,45,132,64,76,32,76,0,0,234,32,15>>

马上就要开学啦,祝高中生们在逛街的时候偶遇到班主任~~~哈哈~~~

时间: 2024-10-11 01:53:23

[Erlang_Question21]Binary为什么可以节省大量的空间?的相关文章

android studio节省C盘空间的配置方法

近期发现C盘空闲空间剩余不多了,经过检查发现在C:\Users\<电脑用户名>\的目录下,有这两个文件夹空间比较大,这两文件夹分别是 .AndroidStudioPreview3.2(不同版本的android studio名称会不一样) 和 .gradle,AndroidStudioPreview3.2存放的是AndroidStudio配置和插件等缓存文件,.gradle存放的是gradle配置和相关依赖文件等内容,这两文件夹加起来有2G多的空间大小,占用了本就紧张的C盘空间.可以通过以下操作

斯蒂芬空间上的法律框架还可节省都会发挥空间

http://www.xiami.com/g/thread-9220428http://www.xiami.com/g/thread-9222326http://www.xiami.com/g/thread-9222791http://www.xiami.com/g/thread-9224108http://www.xiami.com/g/thread-9224586http://www.xiami.com/g/thread-9228237http://www.xiami.com/g/threa

Win8节省C盘空间攻略

问题分析: 1.系统页面文件(虚拟内存)占用空间 2.自动更新的缓存文件 3.系统保护的备份文件(系统还原用的) 4.休眠文件 5.索引文件 6.桌面文件 解决办法: 1.机器是8G内存,完全不需要虚拟内存了,于是右键计算机-〉高级系统设置-〉高级-〉性能-〉设置-〉高级-〉更改,去掉自动管理的勾,点无页面文件,点设置,确定,重启,或者换到别的分区去,刚才点了无页面文件,设置之后再点D盘,点系统管理的大小,点设置,确定,重启即可.减少约8G占用. 2.自动更新缓存文件是可以删除的,C:\WIND

安装新操作系统 Windows 路径设置 节省C盘空间

1.QQ个人文件夹设置到D盘,D:\ProgramData\QQ 2.IE收藏夹设置到D盘,IE缓存设置到D盘 例如我想把收藏夹默认的保存路径改到D:\study下.关闭Internet Explorer浏览器,打开资源管理器,到C:\Documents and Settings\Administrator\,用鼠标左键点住收藏夹图标,然后用左手按住Shift键不放,将收藏夹图标拖到D:\study再放开. 小提示:进行此操作时,一定要先关闭Internet Explorer浏览器,否则没有办法

树状数组(Binary Indexed Tree,BIT)

树状数组(Binary Indexed Tree) 前面几篇文章我们分享的都是关于区间求和问题的几种解决方案,同时也介绍了线段树这样的数据结构,我们从中可以体会到合理解决方案带来的便利,对于大部分区间问题,线段树都有其绝对的优势,今天这篇文章,我们就来欣赏由线段树变形的另外一个数据结构--树状数组,树状数组通常也用于解决区间求和.单点更新的问题,而且效率比线段树高一些(树状数组区间求和和单点更新的时间复杂度均为o(log n)),相对而言,线段树的应用范围可能更广泛一些.但不得不承认,树状数组确

Oracle 表空间管理

Oracle磁盘管理中的最高逻辑层是表空间,Oracle11g中必须创建的4个表空间是SYSTEM,SYSAUX, TEMP, UNDOTBS1. 2 SYSTEM:存储数据字典等,pl/sql代码等. 2 SYSAUX:存储与数据库选项相关的数据 2 TEMP:用于大的排序操作 2 UNDUTBS1:为读一致性和恢复的目的,存储事务信息. 表空间的下一层是段,一个段只能驻留在一个表空间中:一个或多个区可以组成一个段,每个区只能驻留在一个数据文件中:一组连续的数据块可以组成一个区.如果要查询表空

如何计算Java对象占用了多少空间?

在Java中没有sizeof运算符,所以没办法知道一个对象到底占用了多大的空间,但是在分配对象的时候会有一些基本的规则,我们根据这些规则大致能判断出来对象大小. 对象头 对象的头部至少有两个WORD,如果是数组的话,那么三个WORD,内容如下: 对象的HashCode,锁信息等 到对象类型数据的指针 数组的长度(如果是数组的话) 规则 首先,任何对象都是8字节对齐,属性按照[long,double].[int,float].[char,short].[byte,boolean].referenc

Unity3D–Texture图片空间和内存占用分析

Texture图片空间和内存占用分析.由于U3D并没有很好的诠释对于图片的处理方式,所以很多人一直对于图集的大小和内存的占用情况都不了解.在此对于U3D的图片问题做一个实际数据的分析.此前的项目都会存在这样或者那样的打包后包大小与内存占用情况的问题,所以这次所以彻彻底底得分析下U3D对于Texture的处理方式.程序里的内存优化请参考<Unity3d优化之路>.减少U3D包大小请参考<unity3d之如何将包大小减少到极致>. 我打包多种类型的项目,空项目和10张放在Resourc

Oracle表空间基础(2)

一.压缩表空间 压缩表空间是通过压缩表空间内的对象来实现的.数据的压缩体现在数据块上,简单的说就是通过清除数据块上的重复内容来达到降低I/O,提升性能性能的目的.在表空间的创建语句中通过指定default关键字,可以让在该表空间上创建的所有表进行压缩(实际上,压缩是在数据插入时进行的). 根据表空间存储数据对象的不同,表空间压缩类型可以分为OLTP压缩.非结构化文件副本清除.非结构化文件压缩和备份数据压缩等.其中OLTP压缩是指在发生DML操作(包括insert,delete,update)期间