`
litaocheng
  • 浏览: 337703 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

binary优化及相关

阅读更多
R12B中引入了bit string(bits),其包含任意数目的bit,如果其包含的bit数目可以被8整除,那么我们称其为binary(bytes)。
使用bits
有了bits,我们对某些协议的操作更加简便灵活。
比如IS 683-PRL 协议,其首部包含5个bit指示后面有多少个连续的11 bit的数据。
在以前我们要解析其这个数据包了非常繁琐,请看如下:
decode(<<NumChans:5, _Pad:3, _Rest/binary>> = Bin) ->
	decode(Bin, NumChans, NumChans, []).
decode(_, _, 0, Acc) ->
	Acc;
decode(Bin, NumChans, N, Acc) ->
	SkipBef = N * 11,
	SkipAft = (NumChans - N) * 11,
	Pad = 8 - ((NumChans * 11 + 5) rem 8),
	<<_:5, _:SkipBef, V:11, _:SkipAft, _:Pad>> = Bin,
	decode(Bin, NumChans, N-1, [V | Acc]).


是不是很复杂,之所以如此负载,就是因为原来binary拥有数据的最小单位是byte,所以我们只能用很多手法来定位解析我们要的数据。

而现在有了bits,我们可以非常轻松的实现上面的代码:
第一种方法:
decode(<<NumChans:5, Rest/binary>>) ->
	decode(Rest, NumChans, []).

decode(<<V:11, Rest/bits>>, N, Acc) ->
	decode(Rest, N-1, [V | Acc]);
decode(_, 0, Acc) ->
	lists:reverse(Acc).


是不是简洁很多?
我们还有第二种方法:
decode(<<NumChans:5, Chans:NumChans/bits-unit:11, _/bits>>) ->
	[Chan || <<Chan:11>> <= Chans].


binaries的创建
erlang在创建一个binary bin1的时候,会预留一定的空间(整个binary大小为:实际占用空间的2倍或256两者中较大者),这样当我们连续的在尾部添加bin2时,只需要将bin2追加到原binary的预留空间即可,不用重新分配空间,也不用拷贝原有bin1的数据。因此效率很高。
比如
Bits拥有1000个bit的数据,同时拥有600个bit的未使用空间,下面的表达式:

NewBits = <<Bits/bits, 12:32>>,


NewBits只是指向了原有的Bits,同时将32bit的数据追加到Bits中,此时NewBits拥有1032个bit的数据,568个未使用bit。而原有的Bits,此时还是保持原有的数据。
接着你写下了下面的语句:

NewBits2 = <<Bits/bits, 12:64>>,


如果我们还在Bits后面追加,那么显然NewBits2不是我们想要的结果。这里没有优化的可能了。
只能老老实实的创建一个新的binary,然后将Bits1的内容拷贝过来。

binary匹配
如何写出能够binary匹配优化的代码?
1, 牢牢记住下面的代码框架
f(<<Pattern1,...,Rest/bits>>,...) ->
  ... % Rest is not used here
  f(Rest,...);
f(<<Pattern2,...,Rest/bits>>,...) ->
  ... % Rest is not used here
  f(Rest,...);
...
f(<<>>, ...) ->
  ReturnValue


即不要在binary匹配的clause中返回或使用Rest binary,仅仅是将其作为参数传递给下一个自身函数调用。

2,函数中的clause如果是进行binary匹配,那么这些进行匹配的clause需要连续。(后面可以看到一个例子)
这样我们的代码才会被最大程度的binary优化。在这样的函数中,直到函数返回,我们只创建了一个match context,没有创建任何其他的sub binary。
要点就是Rest在代码中不要做任何其他使用,而是直接交给递归函数。
注:match contex和sub binary都是binary的一种,binary在内部实现中共有四种类型,另外两种类型是Refc binaries和
Heap binaries。具体的参看http://www.erlang.org/doc/efficiency_guide /binaryhandling.html#4。需要说明的是match context只在binaries match的时候生成,其比sub binary更加高效。

如何查看我的代码是否执行了binary 优化?
只要加上bin_opt_info选项即可,可以添加在命令行,也可以添加在源文件的-compile属性中:
erlc + bin_opt_info my.erl


%% my.erl
-module(my).
-compile([bin_opt_info]).


binary匹配代码优化举例

通过bin_opt_info编译选项,我们看几个例子,我们把编译器的提示信息作为注释加入到代码中,方便您查看未优化原因。

1, 未优化,因为函数参数的顺序,binary匹配应该在第一位。
non_opt_eq([H|T1], <<H,T2/binary>>) ->
        %% INFO: matching anything else but a plain variable to
        %%    the left of binary pattern will prevent delayed
        %%    sub binary optimization;
        %%    SUGGEST changing argument order
        %% NOT OPTIMIZED: called function non_opt_eq/2 does not
        %%    begin with a suitable binary matching instruction
    non_opt_eq(T1, T2);
non_opt_eq([_|_], <<_,_/binary>>) ->
    false;
non_opt_eq([], <<>>) ->
    true.


优化:
opt_eq(<<H,T1/binary>>, [H|T2]) ->
       opt_eq(T1, T2);
opt_eq(<<_,_/binary>>, [_|_]) ->
    false;
opt_eq(<<>>, []) ->
    true.


2,未优化,不合理的匹配语法,导致无法优化,这里的Bad模式匹配,影响优化。
not_opt_sum1(<<A, Rest/binary>> = Bad, Acc) ->
	%Warning: NOT OPTIMIZED: called function not_opt_sum1/2
        %does not begin with a suitable binary matching instruction
	not_opt_sum1(Rest, A + Acc);
not_opt_sum1(<<>>, Acc) ->
	Acc.


优化:
去掉Bad

3,未优化,sub binary被使用。毫无疑问这里的bit_size使用了Rest.
not_opt_sum2(<<A, Rest/binary>>, Acc) ->
	bit_size(Rest), %Warning: NOT OPTIMIZED: sub binary is used or returned
	not_opt_sum2(Rest, A + Acc);
not_opt_sum2(<<>>, Acc) ->
	Acc.


优化:
去除bit_size(Rest)表达式

4,未优化,sub binary被返回,即第一个clause中 T被返回。
not_opt_zero(<<0, T/binary>>) ->
	T; %Warning: NOT OPTIMIZED: sub binary is used or returned
not_opt_zero(<<A, T/binary>>) ->
	not_opt_zero(T).


优化:
opt_zero(<<0, T/binary>>, not_found) ->
	opt_zero(T, found);
opt_zero(<<A, T/binary>>, _) ->
	opt_zero(T, not_found);
opt_zero(T, found) ->
	T.


5,未优化,多个binary匹配clause不连续导致(这个例子是从avindev的blog偷来的)
extract_str_end_with_tag(Data, Tag) ->
     extract_str_end_with_tag2(Data, <<>>, Tag, not_found).  

extract_str_end_with_tag2(<<Tag, T/binary>>, Buffer, Tag, _) ->
	 extract_str_end_with_tag2(T, Buffer, Tag, found);
extract_str_end_with_tag2(<<B, T/binary>>, Buffer, Tag, not_found) ->
     extract_str_end_with_tag2(T, <<Buffer/binary, B>>, Tag, not_found);
extract_str_end_with_tag2(Rest, Buffer, _, found) ->
	 {found, Buffer, size(Buffer), Rest};
	 % Warning: INFO: non-consecutive clauses that
	 %match binaries will prevent delayed sub binary optimization
extract_str_end_with_tag2(<<>>, Buffer, _Tag, _) ->
     {not_found, Buffer}.


优化:
extract_str_end_with_tag(Data, Tag) ->
     extract_str_end_with_tag2(Data, <<>>, Tag, not_found).  

extract_str_end_with_tag2(<<Tag, T/binary>>, Buffer, Tag, _) ->
	 extract_str_end_with_tag2(T, Buffer, Tag, found);
extract_str_end_with_tag2(<<B, T/binary>>, Buffer, Tag, not_found) ->
     extract_str_end_with_tag2(T, <<Buffer/binary, B>>, Tag, not_found);
extract_str_end_with_tag2(<<>>, Buffer, _Tag, _) ->
     {not_found, Buffer}.
extract_str_end_with_tag2(Rest, Buffer, _, found) ->
	 {found, Buffer, size(Buffer), Rest};


其实在写代码过程中,优化不是一个开始就要做的环节。首先正确实现工程最重要。但是如果我们了解一些优化的方法,写代码时顺手牵羊让代码
更加高效,何乐不为呢?
另外也不可把bin_opt_info的提示作为圣旨,一味追求OPTIMIZED,而扭曲了本来程序的逻辑。

备注:
遇到两个问题:
1:decode(<<NumChans:5, Chans:NumChans/bits-unit:11, _/bits>>) ->
[Chan || <<Chan:11>> <= Chans].
在R12B-3无法编译通过
2;avindev的blog中提出关于binary优化的一个bug? http://avindev.iteye.com/blog/208927

参考:
http://www.erlang.org/doc/efficiency_guide/binaryhandling.html#4
http://www.erlang.se/euc/07/papers/1700Gustafsson.pdf

另外很高兴认识mryufeng,给予我很大帮助!

Update:
1, decode(<<NumChans:5, Chans:NumChans/bits-unit:11, _/bits>>) ->
[Chan || <<Chan:11>> <= Chans].
语法错误! 是理解binary错误, 正确写法:
decode(<<NumChans:5, Chans:NumChans/binary-unit:11, _/bits>>) ->
[Chan || <<Chan:11>> <= Chans].

因为bits(bitstring)默认的unit只能为1, 我们这里指定11,所以编译提示:bit type mismatch (unit) between 11 and 8, 我们将bits改为binary既可.
这里请注意:bits(bitstring)的unit为1, bytes的unit为8, 而binary的unit为1-256
分享到:
评论

相关推荐

    进行binary优化的json解析模块

    标题中的"binary优化的json解析模块"意味着这个模块设计用于快速处理JSON数据,特别关注减少内存消耗和提高解析速度。Erlang的二进制操作非常高效,因为它直接在内存中操作二进制数据,而无需额外的字符串转换步骤。...

    Zemax使用Binary-2面型设计案例,How-to-use-Binary-2.zip

    在光学设计领域,Zemax是一款广泛使用的光学设计软件,它提供了强大的工具来模拟和优化各种光学系统。在本案例中,我们关注的是“Binary-2”面型的使用,这是一种特殊的光学表面类型,用于实现衍射光学元件(DOE)的...

    编译器优化技术Binary Literacy

    《编译器优化技术:Binary Literacy》 编译器优化是编程领域中至关重要的一环,它能够显著提升软件性能,降低资源消耗。本文将深入探讨编译器优化的几个关键层面,包括高、中、低级优化,以及具体的技术如死代码...

    cef_binary64位

    标题中的“cef_binary64位”指的是CEF(Chromium Embedded Framework)的64位二进制版本。CEF是一个开源框架,允许开发人员在他们的应用程序中嵌入Chromium浏览器引擎,从而实现基于Web技术的用户界面。这个框架广泛...

    NPOI 2.2.1 binary package.zip

    5. **性能优化**:NPOI针对大规模数据处理进行了优化,能够高效地处理成千上万行的数据,降低了内存占用,提升了处理速度。 6. **兼容性**:NPOI不仅适用于.NET Framework,还支持.NET Core,这意味着它可以在...

    BinarySearch

    标签包括"源码"和"工具",这可能意味着我们将讨论与二分查找相关的代码实现和可能的应用工具。源码可能是指提供了二分查找的Java实现,即`BinarySearch.java`文件。在这个文件中,我们可能会看到一个或多个方法,...

    java-二叉树binaryTree

    在这个"java-二叉树binaryTree"主题中,我们将深入探讨二叉树的实现、操作以及相关的算法。 在Java编程语言中,二叉树可以被表示为一个类,这个类通常包含指向左右子节点的引用,以及可能包含的数据。下面是一个...

    Binary admin后台管理系统bootstrap模板

    5. **版本控制**:看到模板有版本号(v1.1),意味着需要关注模板的更新,以便获取最新的特性、修复和性能优化。 通过掌握以上知识点,开发者可以有效地利用"Binary admin后台管理系统bootstrap模板"快速构建出满足...

    xml binary soap 序列化

    综上所述,XML二进制SOAP序列化和反序列化是优化Web服务通信的重要技术,它们通过将XML数据转化为更高效的二进制格式,提高了数据传输的效率和性能。理解并熟练掌握这些技术,对于开发高性能的Web服务和客户端应用...

    Binary Surface.rar

    在光学设计领域,Zemax是一款广泛使用的高级光学系统模拟与优化软件。本压缩包"Binary Surface.rar"聚焦于Zemax中的一个特色功能——二元面(Binary Surface)类型,这是一项用于创建复杂相位分布和非传统光学表面...

    Intel Binary Modification Program

    这项技术的核心在于为开发者和系统制造商提供了对Intel处理器及平台固件的定制能力,以适应不同应用场景的需求或者优化系统性能。 **BIOS与VBIOS** BIOS是计算机硬件系统的核心组成部分,它负责在启动时执行初始化...

    Binary Genetic Algorithm_二进制优化_遗传算法_遗传算法;进化优化;_

    在"01 Binary Genetic Algorithm"这个文件中,可能会包含对上述概念的详细解释、实例演示以及实现二进制遗传算法的代码。通过学习和理解这个文件,你可以更好地掌握如何利用遗传算法解决实际的二进制优化问题,并...

    groovy-binary-1.8.6

    总的来说,Groovy-binary-1.8.6是Groovy的一个历史版本,它提供了一套完整的Groovy运行环境,包括运行时库和相关文档,使得开发者可以在Java平台上利用Groovy的灵活性和生产力优势进行开发。随着Groovy的发展,后续...

    alg_gen.rar_binary PSO_genetic binary_genetic pso_pso genetic_sa

    3. **mochila1.m**:这可能是另一个MATLAB文件,可能与背包问题(Knapsack Problem)有关,这是一个典型的优化问题,可以使用遗传算法或粒子群优化来解决。 4. **opt2.pdf**:这可能是一个关于优化问题的PDF文档,...

    ga.rar_GA_binary genetic_ga binary_genetic binary

    在"GA.rar_GA_binary_genetic_ga_binary_genetic_binary"这个压缩包中,重点讨论的是二进制形式的遗传算法(Binary Genetic Algorithm, BGA)。这种算法在处理离散或二进制决策变量的问题时非常有效,例如在组合优化...

    PyPI 官网下载 | psycopg2_binary-2.9.1-cp37-cp37m-win_amd64.whl

    `psycopg2`源代码版需要在安装时编译,这要求用户的环境具有C编译器和相关的开发库。而`psycopg2_binary`是一个预编译的版本,无需编译过程,可以直接安装,这对于那些没有配置完整编译环境或者希望快速部署应用的...

    An Introducton to Binary Decision Diagrams

    二进制决策图(Binary Decision Diagrams,简称BDD)是一种数据结构,用于表示和操作布尔函数。...理解BDD的基本原理及其核心算法,对于从事计算机科学、电子工程和相关领域研究的人来说至关重要。

    BinaryTree-源码.rar

    【标题】:“BinaryTree-源码.rar”是一个与二叉树相关的源代码压缩包,它可能包含各种二叉树数据结构的实现,如二叉搜索树、平衡二叉树(AVL树或红黑树)或者自定义的二叉树结构。这个压缩包可能为学习数据结构与...

    Optimal Binary Search Tree

    在Knuth的经典论文《Optimum Binary Search Trees》中,他首先回顾了二叉查找树的基本概念及工作原理,即通过比较节点值来决定搜索方向,从而实现快速查找。具体来说,当需要在一个二叉查找树中查找某个元素时,可以...

    Matlab的PSO代码-bimetric_binary_pso.zip

    **Matlab中的粒子群优化算法(PSO)详解** 粒子群优化(Particle Swarm Optimization, PSO)是一种基于群体智能的优化算法,源自对鸟群和鱼群集体行为的模拟。在Matlab环境中,PSO被广泛应用在解决各种工程问题,如...

Global site tag (gtag.js) - Google Analytics