转载:【原译】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. 程序应用级 二.系统性能评估标准 影响性 ...
随机推荐
- C 指针使用误区
/** *错误给指针赋常量 *知识点:指针存储内存地址 **/ #include <stdio.h>void main(){ //int *p_int = 123; //错误,不能直接给指 ...
- 使用Frame控件设计Silverlight的导航
这里所说的导航其实就是在Silverlight的页面之间前进后退以及跳转.通过Frame控件配合后台NavigationService类可以很容易的做到页面之间的导航. 这就是工具箱中的Frame控件 ...
- MySQL抓包工具:MySQL Sniffer 和性能优化
简介 MySQL Sniffer 是一个基于 MySQL 协议的抓包工具,实时抓取 MySQLServer 端的请求,并格式化输出.输出内容包访问括时间.访问用户.来源 IP.访问 Database. ...
- brendangregg
http://www.slideshare.net/brendangregg/presentations http://techblog.netflix.com/2015/07/java-in-fla ...
- python 开发在线音乐播放器-简易版
在线音乐播放器,使用python的Tkinter库做了一个界面,感觉这个库使用起来还是挺方便的,音乐的数据来自网易云音乐的一个接口,通过urllib.urlopen模块打开网址,使用Json模块进行数 ...
- python(33)多进程和多线程的区别
多线程可以共享全局变量,多进程不能.多线程中,所有子线程的进程号相同:多进程中,不同的子进程进程号不同. #!/usr/bin/python # -*- coding:utf-8 -*- import ...
- iOS开发之弹出输入框
最近项目里有个需求要弹出输入框,GitHub上搜了一圈没发现太合适的轮子,就自个儿撸了一个,传送门在这里https://github.com/wozyao/ZYInputAlert,有需要的同学可以d ...
- 有趣的switch应用(填入种类,显示响应的价格)
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Hadoop副本数配置
一个文件,上传到hdfs上时指定的是几个副本就是几个.修改了副本数(dfs.replications),对已经上传了的文件也不会起作用.当然可以在上传文件的同时指定创建的副本数hadoop dfs - ...
- 利用eclipse中的各种功能帮助你理解代码
@菜单栏下面,工具栏,有一对黄色的箭头按钮,一个指向左边,一个指向右边,快捷键是Alt+Left/Alt+Right 功能是跳转到你刚刚编辑过的地方 这里的Left/Right指的是左右方向键,可以方 ...