【7.效率指南】3.常见的注意事项

【效率指南】 常见的注意事项

本节列出了一些需要注意的模块和BIF,不仅仅是从性能的角度。

Erlang/OTP Version:24
System Documentation Version:12.0.2
导航:System Documentation - Efficiency Guide - Common Caveats

1.timer模块

使用erlang:senda_after/3erlang:start_timer/3创建定时器,比使用STDLIB中的timer模块高效很多。

timer模块使用了一个单独的进程去管理定时器。如果有很多进程频繁的创建和取消定时器,那么这个进程很容易超载。

timer模块中有一些函数(如timer:tc/3timer:sleep/1),调用时不需要timer(gen_server)进程执行,因此不会有问题。

2.list_to_atom/1

atom结构不会进行垃圾回收。atom被创建后,永远也不会被回收。如果atom数量达到限制(默认1048576个),仿真器将会终止。

因此,在连续运行的系统中,将任意输入的字符串转换为atom是很危险的。如果只允许某些定义规范的atom作为输入,则可以使用list_to_existing_atom/1来避免拒绝服务(denail-of-service)。(所有要用到的atom必须在早期创建好,例如,只在一个模块中使用的atom,在加载模块时就创建好了)

使用list_to_atom/1构建一个atom,像下面这样传递给apply/3,这样的方式开销很大,不建议在时间关键型代码中使用:

`apply(list_to_atom("some_prefix"++Var), foo, Args)`

3.length/1

计算列表长度的时间与列表长度成正比,与tuple_size/1byte_size/1,和bit_size/1相反,这些函数的执行时间都是恒定的。

通常,不需要担心length/1的执行速度,因为它是在C语言中高效实现的。在时间关键型代码中,如果输入的列表很长,你可能想避免这种情况。

length/1的某些用法,可以用模式匹配替代。例如如下代码:

foo(L) when length(L) >= 3 ->
	...

可以重写为:

foo([_,_,_|_]=L) ->
	...

有一个细微的区别,如果L不是一个List结构,那么length(L)会执行失败(译:但是会被when中的catch捕获到,并返回false),而第二个代码片段中,匹配了一个错误的List结构。

4.setelement/3

setelement/3函数会复制它修改的元组。因此,在一个循环中使用setelement/3更新一个元组,每次都会创建新的副本。

元组复制的规则有一个例外,如果编译器发现破坏性更新元组的结果与复制一次元组的结果相同,那么会把setelement/3的调用替换为特殊毁灭性的setelement指令。在下面的代码中,第一个setelement/3会复制元组并修改第九个元素:

multiple_setelement(T0) ->
    T1 = setelement(9, T0, bar),
    T2 = setelement(7, T1, foobar),
    setelement(5, T2, new_value).

下面两个setelement/3调用,在第一个副本元组中进行修改。

应用这样的优化,必须满足如下条件:

  • 索引必须是整型,不能是变量或表达式。
  • 索引顺序必须是降序。
  • 在调用setelement/3之间不可调用其他函数。
  • 首次调用setelement/3的返回值,只能用作后续调用setelement/3的参数

如果代码没法写成上面multiple_setelement/1示例的格式,在一个大型的元组中修改多个元素时,最好的方法是将这个元组转换为一个list,修改完后在转换为元组。

5.size/1

size/1返回Tuple和Binary的大小。

使用BIF的tuple_size/1byte_size/1函数,给编译器和运行时系统提供了更多的优化机会。另一个优点是BIF的这两个函数,给Dialyzer提供了更多的类型信息。

6.split_binary/2

使用匹配来分割binary,通常比split_binary/2函数更加高效。

%%正确的做法
<<Bin1:Num/binary,Bin2/binary>> = Bin


%%错误的做法
{Bin1,Bin2} = split_binary(Bin, Num)

而且,混合使用位语法匹配和split_binary/2函数,可能会阻碍位于法匹配的某些优化。(译:不可混合使用这两种用法)

翻译内容来自官方文档
GitHub地址

posted @ 2021-09-11 18:31  AmazeBug  阅读(64)  评论(0)    收藏  举报