erlang的官方文档部分翻译
2012-04-06 16:16
260 查看
erlang的八个秘密
1. 复杂函数Funs较慢
funs的速度比apply/3要慢,它从实现机制上利用了编译器的小伎俩,速度上比apply/3使用元组和大量精巧设计来的慢。
2. 列表解析比较慢
在以前列表解析是使用funs的方式实现的,因此它的速度是非常慢的。
但现在使用递归函数实现,当然,采用尾递归函数,在末尾多加一个列表反转仍然要快很多。这在下一个秘密中会讲到。
3. 尾递归函数比普通递归函数要快得多
普通递归函数在堆栈上留下了废旧对象的指针,垃圾回收器需要将所有的废旧对象拷贝一份。而在尾递归函数中,原地开栈意味着废旧对象直接被弃掉了
以上是R7B 之前的版本的情况,在R7B 版本中,编译器运行一段代码,用空列表覆盖了指向废旧对象的指针,因此垃圾回收器不用将废旧数据一直保留了。
即便采用了上述优化,采用尾递归仍然要比普通递归函数快得多,为什么呢?
这就与递归函数被调用时占据了多少字节的堆栈有关系。在绝大多数情况下,一个普通递归函数会比一个尾递归函数开辟更多字节的堆栈,正因为如此,垃圾回收器需要被更频繁地使用,而且它需要更多的来回访问堆栈。
在R12B以及更后来的版本中,已经减少了递归函数调用对于堆栈字数的使用,所以在R12B以后的版本中,使用普通递归函数与使用尾递归调用函数再在其末尾使用一个lists:reverse/1反转列表这两种方式使用相同多的空间。
既然如此,那么哪一个更快?
看情况,在Solaris/Sparc 中,普通递归函数稍微快,即便在元素比较多的列表处理上。而在X86中,尾递归比普通递归快 30%.
因此在选择时,若你要极大限度的提升速度,就要进行权衡,因为尾递归调用并非在所有环境中都快于普通递归。
当然,在不必在尾部使用lists:reverse/1进行列表反转的情况下,尾递归是毫无疑问快于普通递归的(比如,写一个函数计算列表中所有整数和)
4. ‘++’运算是非常糟糕的
‘++’运算是无论如何不应该存在的,
例如这样的例子:
naive_reverse([H|T]) ->
naive_reverse(T)++[H];
naive_reverse([]) ->
[].
很显然可以改写成这样:
实际上经验丰富的程序员应该这样:
5. Strings
比较慢
在erlang里面字符串如果处理得不合适将会非常的慢,你需要根据字符串是如何处理的合理地选择 re.erl 模块取代 regexp 模块。
6. 整理 Dets文件非常慢
整理时间与文件中存在的record 数量成正比。
7. BEAM 是一个基于堆栈的字节码的虚拟机(因此慢)
8. 当变量不使用的时候,用‘_’提高程序的速度
这个是之前的优化方法,自从R6B之后编译器就能自动识别不使用的变量了。
1. 复杂函数Funs较慢
funs的速度比apply/3要慢,它从实现机制上利用了编译器的小伎俩,速度上比apply/3使用元组和大量精巧设计来的慢。
2. 列表解析比较慢
在以前列表解析是使用funs的方式实现的,因此它的速度是非常慢的。
但现在使用递归函数实现,当然,采用尾递归函数,在末尾多加一个列表反转仍然要快很多。这在下一个秘密中会讲到。
3. 尾递归函数比普通递归函数要快得多
普通递归函数在堆栈上留下了废旧对象的指针,垃圾回收器需要将所有的废旧对象拷贝一份。而在尾递归函数中,原地开栈意味着废旧对象直接被弃掉了
以上是R7B 之前的版本的情况,在R7B 版本中,编译器运行一段代码,用空列表覆盖了指向废旧对象的指针,因此垃圾回收器不用将废旧数据一直保留了。
即便采用了上述优化,采用尾递归仍然要比普通递归函数快得多,为什么呢?
这就与递归函数被调用时占据了多少字节的堆栈有关系。在绝大多数情况下,一个普通递归函数会比一个尾递归函数开辟更多字节的堆栈,正因为如此,垃圾回收器需要被更频繁地使用,而且它需要更多的来回访问堆栈。
在R12B以及更后来的版本中,已经减少了递归函数调用对于堆栈字数的使用,所以在R12B以后的版本中,使用普通递归函数与使用尾递归调用函数再在其末尾使用一个lists:reverse/1反转列表这两种方式使用相同多的空间。
既然如此,那么哪一个更快?
看情况,在Solaris/Sparc 中,普通递归函数稍微快,即便在元素比较多的列表处理上。而在X86中,尾递归比普通递归快 30%.
因此在选择时,若你要极大限度的提升速度,就要进行权衡,因为尾递归调用并非在所有环境中都快于普通递归。
当然,在不必在尾部使用lists:reverse/1进行列表反转的情况下,尾递归是毫无疑问快于普通递归的(比如,写一个函数计算列表中所有整数和)
4. ‘++’运算是非常糟糕的
‘++’运算是无论如何不应该存在的,
例如这样的例子:
naive_reverse([H|T]) ->
naive_reverse(T)++[H];
naive_reverse([]) ->
[].
很显然可以改写成这样:
naive_but_ok_reverse([H|T], Acc) ->
naive_but_ok_reverse(T, [H]++Acc);
naive_but_ok_reverse([], Acc) ->
Acc.
实际上经验丰富的程序员应该这样:
vanilla_reverse([H|T], Acc) ->
vanilla_reverse(T, [H|Acc]);
vanilla_reverse([], Acc) ->
Acc.
5. Strings
比较慢
在erlang里面字符串如果处理得不合适将会非常的慢,你需要根据字符串是如何处理的合理地选择 re.erl 模块取代 regexp 模块。
6. 整理 Dets文件非常慢
整理时间与文件中存在的record 数量成正比。
7. BEAM 是一个基于堆栈的字节码的虚拟机(因此慢)
8. 当变量不使用的时候,用‘_’提高程序的速度
这个是之前的优化方法,自从R6B之后编译器就能自动识别不使用的变量了。
相关文章推荐
- django 1.8 官方文档翻译: 1-2-6 编写你的第一个Django应用,第6部分
- Sencha Cmd 6 和 Ext JS 6 指南文档(部分官方文档中文翻译)
- DNN皮肤制作官方文档《DotNetNuke Skinning Guide 》翻译(1)—换肤系统需求分析和设计部分
- Jetty9.4官方文档部分翻译【入门+嵌入式开发】
- 对iOS 9 新增的控件 UIStackView 官方文档的翻译 第二部分
- JMeter简介--官方部分翻译文档
- Django 2.0.1 官方文档翻译: 编写你的第一个 Django app,第三部分(Page 8)
- spring-boot官方文档翻译——第三部分
- 对iOS 9 新增的控件 UIStackView 官方文档的翻译 第四部分
- 【AKKA 官方文档翻译】第二部分:创建第一个actor
- Django 2.0.1 官方文档翻译: 编写你的第一个 Django app,第二部分(Page 7)
- spark deploying的官方文档部分翻译
- 【AKKA 官方文档翻译】第三部分:与设备Actor一起工作
- Sencha Cmd 6 和 Ext JS 6 指南文档(部分官方文档中文翻译)
- Apache Cassandra 1.1 项目介绍(逐篇翻译官方文档加一部分评论)
- 【AKKA 官方文档翻译】第四部分:使用设备组
- django 1.8 官方文档翻译: 1-2-1 编写你的第一个Django应用,第1部分
- Django 2.0.1 官方文档翻译:编写你的第一个 Django app,第六部分(Page 11)
- 【AKKA 官方文档翻译】第五部分:查询设备组
- Django 2.0.1 官方文档翻译: 编写你的第一个 Django app,第四部分(Page 9)