Erlang -- Efficiency Guide Erlang 性能的七个误区

2 Erlang 性能的七个误区

有一些真理存活的时间太长了,远远超出了其最佳的存在时期。这或许是因为人与人之间"信息"的传递速度比一篇单一的声明(例如:非尾递归变得更快了。)发布速度要快。

本文尝试消除这些已经成为神话的旧真理(或者半真理)。

2.1 误区:尾递归比非尾递归快的多

根据"真理",使用尾递归构造一个逆序的列表然后再调用 lists:reverse/1 函数比直接使用非尾递归构建一个正序的列表要快。原因是非尾递归比尾递归消耗更多的内存。

在R12B版本之前,这在某种程度上来说是正确的。在R7B版本之前更是如此。在今天,就不是这样了。一般来说,一个非尾递归函数和一个尾递归函数消耗相同数量的内存。通常是不能够预测出它俩谁更快。因此,使用可以使你代码更加整洁的递归方式即可(通常是非尾递归)。

更多关于尾递归和非尾递归的讨论,请看 Erlang’s Tail Recursion is Not a Silver Bullet..

注意
在函数调用结束时,不需要翻转列表的尾递归函数比非尾递归函数的运行速度要快, 根本不构造任何类型项的尾递归函数也是如此(例如:对列表所有元素的求和函数)

2.2 误区:运算符 “++” 总是不好的

说"++" 运算符名声不好,这是不公平的。这可能与以下最低效翻转列表的代码有关:
不建议

naive_reverse([H|T]) ->
    naive_reverse(T)++[H];
naive_reverse([]) ->
    [].

因为 ++ 运算符会复制其左操作数,上述代码的结果会进行重复的复制,导致n2的复杂度。

但是按照以下方式使用 ++ 运算符是可以的。
普通

naive_reverse([H|T]) ->
    naive_reverse(T)++[H];
naive_reverse([]) ->
    [].

列表的每一个元素都只会复制一次,对于 ++ 运算符来说,运算结果ACC是它的右操作数,所以不会被重复复制。

有经验的Erlang开发者会编写如下代码去实现:
建议

vanilla_reverse([H|T], Acc) ->
    vanilla_reverse(T, [H|Acc]);
vanilla_reverse([], Acc) ->
    Acc.

这样做的效率稍微高一些,因为这里构建列表的方式不是直接复制列表,而是往原列表头添加一个元素。(如果编译器不自动将[H]++Acc重写为[H|Acc],那么效率会更高。)

2.3 误区:字符串相关的运算速度很慢

字符串如果处理不当是会变得很慢。在 Erlang,你需要更多一些思考如何使用字符串以及选择一个合适的字符串表示方式。如果你使用正则表达式,请使用 STDLIB 的 re 模块,不要使用过时的 regexp 模块。

2.4 误区:修复 Dets 文件是非常慢的

修复的时间与文件中记录的数量成正比,但是在过去,Dets 修复要慢的多。Dets已经被大量重写和改进。

2.5 误区:BEAM是一种基于堆栈的字节码虚拟机(因此速度很慢)

Beam是一种基于寄存器的虚拟机。它拥有1024个虚拟寄存器,被用于调用函数时保存临时变量和传参。在函数调用时拥有生命周期的变量被压入栈中。
Beam是一个线程代码解释器。每条指令直接指向可执行的C语言代码,调度非常快速。

2.6 误区:当变量不使用时使用 “_” 代替,可以使程序变快。

这曾经是正确的,但是在R6B版本之后,Beam编译器可以分辨出一个变量是没有被使用的。
类似的,在源码级别上的琐碎转换对最终生成的代码没有任何影响。比如将 case 语句转换到函数的第一行。

2.7 误区:NIF总是加速你的程序

重构 Erlang 代码成一个NIF应该是使程序变快的最终手段。因为它只能保证是危险的,并不保证能程序运行得更快。
在NIF里面执行太多的运算过程会降低 VM 的响应性。执行太少可能意味着在NIF中获得更快处理的好处会被调用NIF和检查参数的开销所抵消。
在编写NIF之前请先看Long-running NIFs .

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值