« 一些mac osx不引人注意的工具 | Main | 找个咖啡厅做办公室 »

从case语句的性能说起

作者:virushuo 发表于 2007-01-23 08:01 最后更新于 2007-01-23 18:01
版权声明:按照by-nc-sa的cc协议可转载,拒绝采用“独家” 授权媒介(含网站和平面媒体)转载、引用、链接,除非获得本人许可。转载时请务必以超链接形式标明文章原始出处和作者信息及本声明。


tiny同学给我看了这么一个帖子

这个帖子的楼主认为php里面,一堆case语句的性能很低,所以给改成了用函数调用和eval的方式。

第一眼看上去,我自然就知道这种说法是错的。原因和tiny同学说的差不多。在这个问题上,我突然发现现在写php的人们貌似都不怎么懂汇编?所以才导致一些根本的观念错误。说说我的看法吧:

1 case 在汇编里面应该是jmp ,直接的地址跳转性能很高,而且case的数量多少并不影响效率,也即性能是恒定的。
2 if...else语句在汇编里面是jz和jnz,判断的数量多少会改变效率。性能不是恒定的。所以case 和if...else是不同的。
3 函数调用是低性能的,因为调用函数首先要保持现场,然后进行一次call,最后返回,这中间要进行一堆push和pop操作,比if...else的指令周期要长出来n多,自然慢的多。
4 至于eval这种高级特性,都不用说了,自然比函数调用都要慢出来无数倍。

以上说的自然是c/c++的编译结果,不过天下大道都是一样的,想必同样的cpu和操作系统上,在这种巨大的性能差距面前,恐怕什么语言都不会颠倒过来。

事实上,性能优化和代码好看,从来就不是一件事。好看的代码未必是快的,难看的代码效率未必难看。快速开发工具和脚本语言的大量普及,往往混淆了性能和扩展性这两个方向性完全不同的问题。

扩展性一定是以性能损失为代价的。而极度追求效率的代码自然不会太容易读。回头看这个帖子,似乎用eval改写过的代码,除了看起来高深点,也未必有过去的case方式容易读懂。在cpu非常慢的时候,流行一堆性能优化的手段,现在不知道还在不在用(做游戏的或许还在用),不知底细的,看到这种代码,恐怕也会大骂写的糟糕。列举几条:

1 乘方运算直接写做乘法 2^3要写成 2*2*2
2 乘法运算直接写做加法 2*3 写做 2+2+2
(我怀疑这两条现在编译器是不是可以优化了?不用这么夸张了吧?)
3 不用循环,而是直接把代码贴n遍
4 把if换成case
5 不用函数,用宏,宏在编译期间会直接展开,不会产生刚才说的push和pop

这些方法现在看来有点匪夷所思吧?貌似java/c++的教科书上都在说,宏替换是降低代码可读性和难以维护的罪魁祸首。事实上,OOP和OOD的产生也从来不是为了性能,而是为了复用和软件工程。互联网开发其实和游戏开发比较类似,需要的是较高的性能和稳定性,对复用的要求不那么高,因为这个行当做的是逻辑并不复杂的特定需求。企业开发(典型的就是银行),是因为业务逻辑和组件的高度相似性,才需要复用和高度的工程化。OOP/OOD都是这些行业的救命稻草。在互联网行业,这东西不是那么玩的转的。看到用java和.net开发互联网应用的人,我心里就暗笑——这从一开始就错了啊。

在互联网的服务器开发这个领域,单机的性能优化已经越来越不重要——除了太离谱的。并行和分散压力才是真正的解决问题之道。遗憾的是很多公司根本没意识到这点。当他们挑选开发语言和开发方法的时候,可考虑过正在做什么,未来会怎么样吗?

李小龙解释截拳道时候说过类似于“有用的武功都难看。”之类的话。可见天下道理都有那么几分相通之处。

做一件事情之前,一定要先明确要做什么,目的是什么。否则就会陷入困境。

纯粹的OOP观念上,要尽量少用if...else什么的判断。单从易读的角度来看,多态真的比if或case好读懂吗?我真的不这么认为。我更相信,除了很少的时候是为了扩展,更多的时候是根本不怎么懂技术的技术领导不懂装懂,或是程序员为了显示自己水平够高故意写成那样的。

又想起来那个初级程序员到hacker高手们写打印"hello world"程序的笑话,顶尖高手就用一句:
echo "hello world!"

大道至简,莫过于此。
-------------------------------
update:看到有匿名为哈哈的用户在我的sinablog留言,问我是否看过case编译后的汇编结果。那么就多说两句。

1 看过。我也曾怀疑过windows消息循环所用的大量case是否会导致性能下降,所以专门试验过。当然汇编的结果和编译器有一定关系。其实这里还涉及了编译器优化的问题。少量的分支case确实会被优化为jnz之类的条件分支,这时候和if..else没本质区别,但大量的case则会被优化成jmp+ 跳转地址表的方式。所以使用大量case远比大量的if..else快。现代的编译器结果都应该是这样的。

2 系统设计当然是整体的事情,尤其是互联网服务。本文中亦有提到。质疑之前还请看完原文。

blog comments powered by Disqus
CC License. Some rights reserved.
署名·非商业用途·保持一致
本站之所有未作特别说明的内容均使用 创作共用协议.
POWERED_BY_MT_3.2