转载:【原译】Erlang常见注意事项(Efficiency Guide)

简介: 转自:http://www.cnblogs.com/futuredo/archive/2012/10/17/2726416.html   Common Caveats(常见注意事项) Erlang/OTP R15B02   Here we list a few modules and BIFs to watch out for, and not only from a performance point of view.   这里我们列出了需要注意的一些模块和内置函数,不仅仅是从性能的角度来看。

转自:http://www.cnblogs.com/futuredo/archive/2012/10/17/2726416.html

 

Common Caveats(常见注意事项)

Erlang/OTP R15B02

  Here we list a few modules and BIFs to watch out for, and not only from a performance point of view.

  这里我们列出了需要注意的一些模块和内置函数,不仅仅是从性能的角度来看

  1  The timer module

  定时器模块

  Creating timers using erlang:send_after/3 and erlang:start_timer/3 is much more efficient than using the timers provided by the timer module. The timer module uses a separate process to manage the timers, and that process can easily become overloaded if many processes create and cancel timers frequently (especially when using the SMP emulator).

  使用 erlang:send_after/3和erlang:start_timer/3来生成定时器比用timer模块提供的定时器效率要高的多。 timer模块使用一个分离的进程来管理定时器,而且如果很多进程频繁地创建和取消这些计时器(特别是当使用SMP模拟器时),那个管理进程很容易负载过 重。

  The functions in the timer module that do not manage timers (such as timer:tc/3 ortimer:sleep/1), do not call the timer-server process and are therefore harmless.

  那些在timer模块中的不用来管理定时器的函数(例如,timer:tc/3,timer:sleep/1),不调用timer-server进程,因此是无害的。

  2  list_to_atom/1

  list_to_atom/1函数

  Atoms are not garbage-collected. Once an atom is created, it will never be removed. The emulator will terminate if the limit for the number of atoms (1048576 by default) is reached.

  原子是不会被垃圾回收器回收的。一旦一个原子被创建,它将永远不会被移除。如果原子的数量达到了限制数量(默认是1048576),模拟器会终止。

  Therefore, converting arbitrary input strings to atoms could be dangerous in a system that will run continuously. If only certain well-defined atoms are allowed as input, you can use list_to_existing_atom/1 to guard against a denial-of-service attack. (All atoms that are allowed must have been created earlier, for instance by simply using all of them in a module and loading that module.)

  因此,在一个 持续运转的系统中,将任意的字符串输入转换为原子是危险的。如果只允许输入某些良好定义的原子,你可以使用 list_to_existing_atom/1函数,来防范denial-of-service攻击(拒绝服务攻击)。(所有被允许的原子必须先创建 好,比如在一个模块中使用,然后再加载那个模块)

  Using list_to_atom/1 to construct an atom that is passed to apply/3 like this

  像下面这样使用list_to_atom/1函数来构建一个原子,然后传给apply/3

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

  is quite expensive and is not recommended in time-critical code.

  代价相当大,在时间因素很重要的代码里不推荐这样使用

  3  length/1

  length/1函数

  The time for calculating the length of a list is proportional to the length of the list, as opposed to tuple_size/1byte_size/1, and bit_size/1, which all execute in constant time.

  计算列表长度的时间和这个列表的长度成正比,相反的,tuple_size/1,byte_size/1,bit_size/1都在常量时间内计算。

  Normally you don't have to worry about the speed of length/1, because it is efficiently implemented in C. In time critical-code, though, you might want to avoid it if the input list could potentially be very long.

  通常你不必担心length/1函数的速度,因为它是用C来有效实现的。尽管如此,在时间因素很重要的代码里,如果输入的列表有可能会非常长,你仍然可能会避免使用它。

  Some uses of length/1 can be replaced by matching. For instance, this code

  一些length/1函数的使用情况可以用匹配来替代。比如,下面代码

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

  can be rewritten to

  可以被重写成

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

  (One slight difference is that length(L) will fail if the L is an improper list, while the pattern in the second code fragment will accept an improper list.)

  (一点轻微的不同在于,如果输入L是个不合适的列表,length(L)会执行失败,但是第二个代码块中的匹配方法能够接收不合适的列表)

  4  setelement/3

  setelement/3函数

  setelement/3 copies the tuple it modifies. Therefore, updating a tuple in a loop usingsetelement/3 will create a new copy of the tuple every time.

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

  There is one exception to the rule that the tuple is copied. If the compiler clearly can see that destructively updating the tuple would give exactly the same result as if the tuple was copied, the call to setelement/3will be replaced with a special destructive setelement instruction. In the following code sequence

  对于这种复制元组的规则,有一个例外。如果编译器可以清楚的知道,这种破坏性的更新会产生跟复制一样的结果,那么一种特殊的setelement指令会代替原有的对setelement/3函数调用。下面的代码序列中

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

  the first setelement/3 call will copy the tuple and modify the ninth element. The two following setelement/3 calls will modify the tuple in place.

  第一个setelement/3函数会复制元组并修改第九个元素。后面两个setelement/3函数会原地修改这个元组。

  For the optimization to be applied, all of the followings conditions must be true:

  •   The indices must be integer literals, not variables or expressions.
  •   The indices must be given in descending order.
  •   There must be no calls to other function in between the calls to setelement/3.
  •   The tuple returned from onesetelement/3 call must only be used in the subsequent call to setelement/3.

  只有在下面的这些条件都成立时,才能执行优化:

    索引必须是整数字符,不能是变量或者表达式

    索引必须是降序的

    在连续的setelement/3调用之间,不能有其他的函数处理。

    一个setelement/3函数的返回结果必须只能用在随后的setelement/3函数中

  If it is not possible to structure the code as in the multiple_setelement/1 example, the best way to modify multiple elements in a large tuple is to convert the tuple to a list, modify the list, and convert the list back to a tuple.

  如果不能像multiple_setelement/1例子一样构建代码,在一个大型的元组中修改多个元素的最佳方式就是,把元组转换成一个列表,修改列表,再把列表改回成元组。

  5  size/1

  size/1函数

  size/1 returns the size for both tuples and binary.

  size/1函数返回元组或者二进制串的大小。

  Using the new BIFs tuple_size/1 andbyte_size/1 introduced in R12B gives the compiler and run-time system more opportunities for optimization. A further advantage is that the new BIFs could help Dialyzer find more bugs in your program.

  使用R12B版本中新引入的内置函数tuple_size/1和byte_size/1,能够让编译器和虚拟机做更多的优化。进一步的优点就是新的内置函数能够帮助Dialyzer发现程序中更多的bug。

  6  split_binary/2

  split_binary/2函数

  It is usually more efficient to split a binary using matching instead of calling thesplit_binary/2 function. Furthermore, mixing bit syntax matching andsplit_binary/2 may prevent some optimizations of bit syntax matching.

  相比较调用split_binary/2函数来分解一个二进制串而言,匹配通常更加有效。而且,混合使用bit语法匹配和split_binary/2函数,可能会阻碍某些bit语法匹配的优化工作。

  DO

        <<Bin1:Num/binary,Bin2/binary>> = Bin,

  DO NOT

        {Bin1,Bin2} = split_binary(Bin, Num)
        

  7  The '--' operator

  '--'操作符

  Note that the '--' operator has a complexity proportional to the product of the length of its operands, meaning that it will be very slow if both of its operands are long lists:

  注意,'--'操作符的复杂度和它的操作数的长度的乘积成正比,这表示,如果两个操作数是长列表,那么它的处理会很慢:

  DO NOT

        HugeList1 -- HugeList2

  Instead use the ordsets module:

  要使用ordsets模块:

  DO

        HugeSet1 = ordsets:from_list(HugeList1),
        HugeSet2 = ordsets:from_list(HugeList2),
        ordsets:subtract(HugeSet1, HugeSet2)
        

  Obviously, that code will not work if the original order of the list is important. If the order of the list must be preserved, do like this:

  很显然,如果原来的列表中元素的顺序很重要,那么上面的代码是行不通的。如果列表中元素的顺序必须保留,那么像这样做:

  DO

        Set = gb_sets:from_list(HugeList2),
        [E || E <- HugeList1, not gb_sets:is_element(E, Set)]

  Subtle note 1: This code behaves differently from '--' if the lists contain duplicate elements. (One occurrence of an element in HugeList2 will remove all occurrences in HugeList1.)

  细节事项1:如果列表中包含重复的元素,那么这块代码跟'--'操作符的效果不同。(HugeList2中出现一个元素即会删掉HugeList1中所有重复的这个元素)

  Subtle note 2: This code compares lists elements using the '==' operator, while '--' uses the '=:='. If that difference is important,sets can be used instead of gb_sets, but note that sets:from_list/1 is much slower than gb_sets:from_list/1 for long lists.

  细节事项2: 这块代码使用'=='来比较列表元素,而'--'操作符使用'=:='来比较列表元素。如果这个区别显得很重要,那么可以用sets模块来替代 gb_sets模块,但是记住,对于长列表,sets:from_list/1函数比gb_sets:from_list/1函数要慢得多。

  Using the '--' operator to delete an element from a list is not a performance problem:

  使用'--'操作符来删除列表中的一个元素不存在性能问题:

  OK

        HugeList1 -- [Element]
相关文章
|
Shell 网络架构
《cowboy 源代码分析第一部 (Erlang实现的http服务器)》
cowboy是基于ranch的http服务器。特点是功能强打(支持完整的http协议websocket,spdy等),简洁,轻量级。
《cowboy 源代码分析第一部 (Erlang实现的http服务器)》
|
安全 网络安全 数据安全/隐私保护
SSL案例:湖北、厦门、青岛电子税务局HTTPS证书应用
国家税务总局湖北、厦门、青岛(省、市)税务局,作为第二批优化税收营商环境试点单位,积极推动本省市电子税务局建设工作,纷纷在2018年底前正式上线本省市电子税务局。
2489 0
|
5月前
|
机器学习/深度学习 人工智能 算法
Python+YOLO v8 实战:手把手教你打造专属 AI 视觉目标检测模型
本文介绍了如何使用 Python 和 YOLO v8 开发专属的 AI 视觉目标检测模型。首先讲解了 YOLO 的基本概念及其高效精准的特点,接着详细说明了环境搭建步骤,包括安装 Python、PyCharm 和 Ultralytics 库。随后引导读者加载预训练模型进行图片验证,并准备数据集以训练自定义模型。最后,展示了如何验证训练好的模型并提供示例代码。通过本文,你将学会从零开始打造自己的目标检测系统,满足实际场景需求。
3143 0
Python+YOLO v8 实战:手把手教你打造专属 AI 视觉目标检测模型
|
12月前
|
开发框架 JavaScript 前端开发
Electron 重大更新,33.0.0版本发布,带来多项新特性与改进!
本文介绍了 Electron 33.0.0 版本的重要更新,包括核心组件的升级(Chromium、Node.js 和 V8),新增功能(如 app.setClientCertRequestPasswordHandler 和 View.setBorderRadius),重要改进和主要问题修复。建议开发者尽快升级,以享受更强大的性能和功能。
543 0
Electron 重大更新,33.0.0版本发布,带来多项新特性与改进!
|
12月前
|
iOS开发 MacOS Windows
electron-updater实现electron全量版本更新
electron-updater实现electron全量版本更新
1906 9
electron-updater实现electron全量版本更新
|
11月前
|
传感器 安全 Java
如何使用 CoAP 协议进行设备通信
CoAP(Constrained Application Protocol)是一种适用于资源受限设备的轻量级协议,常用于物联网(IoT)设备之间的通信。本文介绍如何使用 CoAP 协议进行设备通信,包括协议的基本概念、消息格式、请求与响应流程以及实际应用示例。
1452 3
|
12月前
|
JavaScript API
使用vue3+vite+electron构建小项目介绍Electron进程间通信
使用vue3+vite+electron构建小项目介绍Electron进程间通信
1447 3
简单易操作 VsCoe离线安装插件【步骤+图片+插件】
这篇文章介绍了在Visual Studio Code (VSCode) 中进行离线安装插件的详细步骤,包括如何下载插件、以SVN插件为例的离线安装过程、通过命令行安装以及一个更加简单的离线安装方式,还提供了操作界面的截图帮助理解。
简单易操作 VsCoe离线安装插件【步骤+图片+插件】
正则表达前一个元素至少出现一次
正则表达前一个元素至少出现一次
437 4
|
传感器 数据采集 监控
毕业设计|基于51单片机的配电室远程监控系统设计环境检测GSM环境报警设计
毕业设计|基于51单片机的配电室远程监控系统设计环境检测GSM环境报警设计
227 0