转载:【原译】Erlang性能的八个误区(Efficiency Guide)
转自:http://www.cnblogs.com/futuredo/archive/2012/10/16/2725770.html
The Eight Myths of Erlang Performance
Erlang/OTP R15B02
1 Myth: Funs are slow
Fun函数很慢(这里应该是指Module:Function(Arguments)这种形式的函数,其中M,F,A可以是变量类型,值不是固定的)
Yes, funs used to be slow. Very slow. Slower than apply/3. Originally, funs were implemented using nothing more than compiler trickery, ordinary tuples, apply/3, and a great deal of ingenuity.
是的,fun函数曾经很慢,非常慢,比apply/3方式还慢。最开始,fun函数只是通过编译器策略,普通元组,apply/3方式和其他一些新的东西来实现的。
But that is ancient history. Funs was given its own data type in the R6B release and was further optimized in the R7B release. Now the cost for a fun call falls roughly between the cost for a call to local function and apply/3.
但是那已经是过去的历史,在R6B版本中,fun函数有了自己的数据结构,在R7B版本中,fun函数进一步做了优化。现在一个fun函数调用的耗费大概在本地函数调用和apply/3方式之间。
2 Myth: List comprehensions are slow
列表解析很慢
List comprehensions used to be implemented using funs, and in the bad old days funs were really slow.
列表解析以前是使用函数来实现的,而在糟糕的以前,函数非常慢。
Nowadays the compiler rewrites list comprehensions into an ordinary recursive function. Of course, using a tail-recursive function with a reverse at the end would be still faster. Or would it? That leads us to the next myth.
现在,编译器把列表解析重新写成一个普通的递归函数。当然,使用一个尾递归函数并且在最后反转效率将更快。是吗?让我们来看看下一个因素。
3 Myth: Tail-recursive functions are MUCH faster than recursive functions
尾递归函数比普通递归函数快得多
According to the myth, recursive functions leave references to dead terms on the stack and the garbage collector will have to copy all those dead terms, while tail-recursive functions immediately discard those terms.
谈到这个误区,递归函数把对不需要的数据引用保留在了堆栈上,垃圾回收器将必须拷贝所有这些不需要的数据,相反,尾递归函数会立即抛弃这些不需要的数据。
That used to be true before R7B. In R7B, the compiler started to generate code that overwrites references to terms that will never be used with an empty list, so that the garbage collector would not keep dead values any longer than necessary.
那种情况在R7B版本之前是对的,在R7B版本中,编译器开始通过使用一个空列表覆写那些将不会被用到的数据引用来产生代码,所以垃圾回收器在没必要的时候就可以不保留那些不需要的值。
Even after that optimization, a tail-recursive function would still most of the time be faster than a body-recursive function. Why?
即使是在优化过后,一个尾递归函数在大多数时候还是比一个体递归要快速,为什么?
It has to do with how many words of stack that are used in each recursive call. In most cases, a recursive function would use more words on the stack for each recursion than the number of words a tail-recursive would allocate on the heap. Since more memory is used, the garbage collector will be invoked more frequently, and it will have more work traversing the stack.
这个跟每次递归调用中有多少个字的堆栈空间被使用有关。在大多数情况下,一个普通递归调用每次占用堆栈空间的大小比尾递归要多。由于更多的内存被使用,垃圾回收器将被更频繁地唤醒,并花费更多的工作来遍历整个堆栈。
In R12B and later releases, there is an optimization that will in many cases reduces the number of words used on the stack in body-recursive calls, so that a body-recursive list function and tail-recursive function that calls lists:reverse/1 at the end will use exactly the same amount of memory. lists:map/2, lists:filter/2, list comprehensions, and many other recursive functions now use the same amount of space as their tail-recursive equivalents.
在R12B及 以后的版本中,做了一个优化,使得在许多情况下能减小体递归调用时在堆栈上占用的空间,所以一个体递归函数和一个尾递归函数,同样在最后调用 lists:reverse/1函数实现列表反转,所使用的内存空间几乎相等。现在,lists:map/2,lists:filter/2,列表解析, 以及许多其他普通递归函数占用的内存空间跟它们的尾递归实现一样。
So which is faster?
那哪一个更快?
It depends. On Solaris/Sparc, the body-recursive function seems to be slightly faster, even for lists with very many elements. On the x86 architecture, tail-recursion was up to about 30 percent faster.
根据情况有所不同。在Solaris/Sparc上,体递归函数看起来稍微快一点,即使对于那些有很多元素的列表。在x86架构上,尾递归要比体递归快近30%。
So the choice is now mostly a matter of taste. If you really do need the utmost speed, you must measure. You can no longer be absolutely sure that the tail-recursive list function will be the fastest in all circumstances.
所以现在怎么选择只是一个喜好的问题。若果真的需要极快的速度,你必须衡量一下。你不再能保证在所有的情况下,尾递归列表函数是最快的。
Note: A tail-recursive function that does not need to reverse the list at the end is, of course, faster than a body-recursive function, as are tail-recursive functions that do not construct any terms at all (for instance, a function that sums all integers in a list).
注意:一个不需要在最后反转列表的尾递归函数,当然比一个体递归函数快,尾递归函数不构造任何数据项(例如,一个计算列表中所有整数的和的函数)
4 Myth: '++' is always bad
'++'总是不好的
The ++ operator has, somewhat undeservedly, got a very bad reputation. It probably has something to do with code like
++操作符有一个不好的声誉,某种程度上不应该是这样的。这个可能跟下面的代码有关
DO NOT
naive_reverse([H|T]) ->
naive_reverse(T)++[H];
naive_reverse([]) ->
[].
which is the most inefficient way there is to reverse a list. Since the ++ operator copies its left operand, the result will be copied again and again and again... leading to quadratic complexity.
这是反转一个列表最低效率的方式。由于++操作符复制它左边的操作数,得到的结果会被一遍又一遍的复制......导致二次方的复杂度
On the other hand, using ++ like this
另一方面,像这样使用++操作符还好
OK
naive_but_ok_reverse([H|T], Acc) ->
naive_but_ok_reverse(T, [H]++Acc);
naive_but_ok_reverse([], Acc) ->
Acc.
is not bad. Each list element will only be copied once. The growing result Acc is the right operand for the ++ operator, and it will not be copied.
每个列表元素将仅被复制一次。增长中的结果是++操作符的右操作数,不会被复制。
Of course, experienced Erlang programmers would actually write
当然,有经验的Erlang程序员实际上会这样做
DO
vanilla_reverse([H|T], Acc) ->
vanilla_reverse(T, [H|Acc]);
vanilla_reverse([], Acc) ->
Acc.
which is slightly more efficient because you don't build a list element only to directly copy it. (Or it would be more efficient if the the compiler did not automatically rewrite [H]++Acc to [H|Acc].)
这个略微更有效率,因为你不再构建一个列表元素,只是直接复制它而已。(如果编译器不自动将[H]++Acc重写为[H|Acc],那上面的写法会更有效)
5 Myth: Strings are slow
字符串很慢
Actually, string handling could be slow if done improperly. In Erlang, you'll have to think a little more about how the strings are used and choose an appropriate representation and use the re module instead of the obsolete regexp module if you are going to use regular expressions.
实际上,字符串处理如果做得不适当会显得很慢。在Erlang中,你将不得不稍稍多思考一下字符串是怎样被使用的,并选择一个恰当的展现方式,如果你要用正则表达式,使用re模块,不要用旧的regexp模块。
6 Myth: Repairing a Dets file is very slow
修复一个Dets文件非常慢
The repair time is still proportional to the number of records in the file, but Dets repairs used to be much, much slower in the past. Dets has been massively rewritten and improved.
现在的修复时间仍然和文件里记录的数目成正比,但是Dets文件的修复在以前要慢很多很多。Dets已经被大量地做了重写和改进。
7 Myth: BEAM is a stack-based byte-code virtual machine (and therefore slow)
BEAM是一个基于堆栈的字节码虚拟机(因此很慢)
BEAM is a register-based virtual machine. It has 1024 virtual registers that are used for holding temporary values and for passing arguments when calling functions. Variables that need to survive a function call are saved to the stack.
BEAM是一个基于寄存器的虚拟机。它有1024个用来存储临时变量和在调用函数时传参的寄存器。在函数调用期间需要存在的变量被保存在堆栈中。
BEAM is a threaded-code interpreter. Each instruction is word pointing directly to executable C-code, making instruction dispatching very fast.
BEAM是一个threaded-code(螺纹代码?)解释器。每条指令直接指向可执行C代码,使得指令调度非常快。
8 Myth: Use '_' to speed up your program when a variable is not used
用'_'来表示不使用的变量来加快你的程序
That was once true, but since R6B the BEAM compiler is quite capable of seeing itself that a variable is not used.
这个以往是正确的,但是自R6B版本以来,BEAM编译器完全有能力注意到有个变量未被使用。
转载:【原译】Erlang性能的八个误区(Efficiency Guide)的更多相关文章
- 转载:【原译】Erlang列表处理(Efficiency Guide)
转自:http://www.cnblogs.com/futuredo/archive/2012/10/22/2734186.html List handling 1 Creating a list ...
- 转载:【原译】Erlang常见注意事项(Efficiency Guide)
转自:http://www.cnblogs.com/futuredo/archive/2012/10/17/2726416.html Common Caveats(常见注意事项) Erlang/OTP ...
- 转载:【原译】Erlang构建和匹配二进制数据(Efficiency Guide)
转自:http://www.cnblogs.com/futuredo/archive/2012/10/19/2727204.html Constructing and matching binarie ...
- 转载:erlang程序优化点的总结
erlang程序优化点的总结(持续更新) 转自:http://wqtn22.iteye.com/blog/1820587 转载请注明出处 注意,这里只是给出一个总结,具体性能需要根据实际环境和需要来确 ...
- 【转载】PHP性能优化干货
PHP优化对于PHP的优化主要是对php.ini中的相关主要参数进行合理调整和设置,以下我们就来看看php.ini中的一些对性能影响较大的参数应该如何设置. # vi /etc/php.ini (1) ...
- 【转载】Spark性能优化指南——高级篇
前言 数据倾斜调优 调优概述 数据倾斜发生时的现象 数据倾斜发生的原理 如何定位导致数据倾斜的代码 查看导致数据倾斜的key的数据分布情况 数据倾斜的解决方案 解决方案一:使用Hive ETL预处理数 ...
- 【转载】 Spark性能优化指南——基础篇
转自:http://tech.meituan.com/spark-tuning-basic.html?from=timeline 前言 开发调优 调优概述 原则一:避免创建重复的RDD 原则二:尽可能 ...
- [转载]U3d常规性能优化技巧
以下技巧并不是必须的,但是对于想要提升游戏性能的人来说应该还是很不错的. 优化的常规技巧 n 剖析你的游戏. 不要花费时间来优化那些晦涩的代码或者缩减图形文件的大小,除非这是你游戏的瓶颈.第一次剖析你 ...
- [转载]Linux服务器性能评估与优化
转载自:Linux服务器性能评估与优化 一.影响Linux服务器性能的因素 1. 操作系统级 CPU 内存 磁盘I/O带宽 网络I/O带宽 2. 程序应用级 二.系统性能评估标准 影响性 ...
随机推荐
- Eclipse color theme jsp javascript显示问题
Q: 在eclipse 中,设置为sublime格式时, 在编辑器中,jsp中嵌套的javascript底色非常难看. A:在如下位置进行设置,Window -> Preferences-> ...
- 《Effective Java》读书笔记七(通用程序设计)
No45 将局部变量的作用域最小化 要使局部变量的作用域最小化,最有力的方法就是在第一次使用它的地方声明. 几乎每个局部变量的声明都应该包含一个初始化表达式.如果你还没有足够的信息来对一个变量进行有意 ...
- Excel中不常用的一些公式用法
INDIRECT函数 http://baike.baidu.com/view/3222185.htm 用于使用单元格内容拼凑公式的情况. 1.采用 [工作表名]!单元格名 的形式读取内容: 2.所 ...
- cocos2d-x开发记录:二,基本概念(导演,场景,层和精灵,场景切换,效果)
四,Director Scene Layer和Sprite(导演,场景,层和精灵) 1.Scenes(场景) 一个场景 (用CCScene对象实现)相当于APP工作流的独立部分.一些人也喜欢叫做“屏幕 ...
- HTML5 CSS3 专题 :诱人的实例 3D旋转木马效果相冊
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/32964301 首先说明一下创意的出处:http://www.zhangxinxu ...
- 经纬度、时分秒转换的C#类
一:新建一个包含经纬度.时间转换的类optaDataConvert public class optaDataConvert { /// <summary> /// 时间转换 /// &l ...
- ny488 素数环
素数环 时间限制:1000 ms | 内存限制:65535 KB 难度:2 描述 有一个整数n,把从1到n的数字无重复的排列成环,且使每相邻两个数(包括首尾)的和都为素数,称为素数环. 为了简便起 ...
- 六、从length和length()方法开始
首先你可以快速回答下面问题吗.当没有任何IDE的情况下,如何得到一个数组的长度,如何得到一个String的长度.我问这个了很对不同水平的开发者:初级的中级的.他们不能快速正确的回答这个问题.当IDE提 ...
- C中fread()函数的返回值
这个问题很容易搞错,并导致很多问题,需要强调的是fread函数返回的并不是字节数. realRead = fread(buf,item,count,fp) (每次读item大小的数据块,分cou ...
- draw sin
draw sin Steps 导入包 生成X轴,Y轴的数据点 设置输出图大小,像素,前景色 指定线宽,线型,绘制曲线 设置坐标轴范围 显示图形. Code #!/usr/bin/env python ...