主题:【讨论】解释执行类代码的性能有无可能达到甚至超过本机编译代码 -- 老兵帅客
咋天的讨论中看到老轧的一个帖子(http://www.cchere.com/article/215508)说C#的运行性能最终将超过C++,我对此感到有些怀疑。虽然对某些频繁使用的代码段来说性能接近是可能的(本机码高速缓存部分消除了反复转换的必要),但是也只是接近而很难超过后者,因为超过后者所需要的跟踪分析和动态优化的开销值得考虑,特别是当程序跳转的范围比较大的时候,这种优化的费效比值得怀疑。
以上是我的一点想法,欢迎有兴趣者参与讨论。
谢谢。
他原文中提到的是"JAVA/NET"效能能提高是因为动态优化.
也就是说, 它是通过同操作系统拉关系, 走后门. 就好象你
用C编的CGI在用户多时不如PHP/PERL一样.
要说跟它们比速度, 我把我的程序就编到LINUX内核里, 跑起来我最大,
什么JAVA,.NET. 谁能有我快? 呵呵.
The point being:
Run-time dynamic optimization will eventually surpass compile-time static optimization.
当然这有一个前提,假设C++的优化技术不再提高了。
现在微软在测试一种叫做Profile-based C++优化技术,在大多情况下,可以有30%左右的性能提高。其特点有点像Hot spot JVM,观察程序的具体运行一段时间(尽量模拟典型情况),生成一个Profile,然后根据这个Profile对程序再次进行优化。理论上讲,这就是一种dynamic optimization,这是传统C/C++编译器做不到的。
其实这种技术既不是微软发明的,也不是Sun的独创,当年的Bull机器(记得是Bull7000)就有这样的能力。
这个方法的核心就是对一段时间的执行特点作Profiler,它假定这个执行特点是稳定的,这样可以缩小工作集的大小,从而在一定程度上提高性能。但是其代价就是Profiler的开销,如果Profiler是由硬件完成的,并行可以减少性能损失;而如果Profiler完全靠软件来做,执行特点的稳定程度就成为至关重要的考虑因素了,否则就有可能得不偿失。
在软件中经常存在这样的情况:一个程序中不同的执行路径存在着不同的执行概率。对于概率差距比较明显的程序,上述优化方法的效果将会比较明显,否则意义不是很大。
忽然想起来,PC上似乎也存在一种优化器,可以根据程序的执行特点作Profiler,然后优化原有的.obj文件来生成新的可执行文件,这个思想和上面所讨论的是类似的,可惜那个优化器的名字想不起来了。
Java 的VM是混合型的。简单的运算是解释执行,费时的反复进行的操作进行编译,生成本机代码。这部优化工作可以超过C++的静态优化,因为它现在更了解程序运行的特点。而C++/C的编译器在生成本机代码的时候没有这些信息。那么为什么不将所有的Code在运行前编译成本机代码呢。Sun的理论是“磨刀有时会误砍柴功”。编译和优化是有代价的。只有当收获大于开销的时候才有意义。基于这个原理,Hotspot JVM要观察程序的运行一段时间才能决定哪些操作有必要优化。
微软的CLR是JIT技术。也就是在运行前,MSIL要转化为本机代码。这种技术早期的Java使用过,但后来放弃了。不知道为什么微软使用这种技术。在实施细节上,CLR和JVM也有些不同。
这样Hotspot的部分同样能够被优化,
而非Hotspot的部分VM是解释执行,
而C是静态优化过的本机代码
这样在理论上,解释执行的语言在性能上永远
不能超过本机编译的代码。
他们在内部进行各种测试,尽量覆盖最常用的操作,然后在这个基础上进行优化。这样生成的Code发布给用户(还可以针对不同的平台最优化)。
用户拿到的Code是成品,在绝大多数情况下,可以获得更好的性能!
说什么有什么C做不到的.系统都是C写的, 有什么做不到的?
什么C不进行优化,..., 问题是这么问的么?
“解释执行类代码的性能有无可能达到甚至超过本机编译代码 ”
解释执行的代码有其固有的缺点,但是赞成“解释执行类代码的性能有可能达到甚至超过本机编译代码”者的 Argument是 VM有一些优点,比如动态优化。
但是这种优点是不是象C语言这样的编译执行方式做不到,或者很难做到的?
如果答案是否定的,那么上述赞成者的Argument就不太成立。
这个说的是发布优化过的代码,而上面说的是优化技术和过程的收益/成本。
这样说吧, 能在计算机上实现的东西,
没有什么是C编译不出来的, 什么动态管理爱...blah..blah..blah..
编译器自己还是C写的讷. 自己编动态管理不就完了...
动态管理很神秘么?
它不可能预见程序在编译后会怎么运行,有什么具体特点,因为那是Run-time的行为。这些信息只有在程序运行的时候,JVM/CLR才可以获得,这是动态优化的根据。
这不是说C/C++编译器不够聪明。这是由于C/C++这种语言的特点决定的。它避免了很多运行时的开销(C++还有一些运行时的开销,所以C++比C还要慢一些),但同时也失去了运行时的许多有用的信息。一种观点认为基于这些信息的优化技术一定会超过编译时的静态优化。这种理论在局部取得了成功,但就大面积而言,还没有!
一个是它太老了,那么多的新生语言使得它的生存空间基本只剩下高级汇编这一点了,这样给它做工作的动力就不足了。
另一个是它的显式指针,显式指针(而不是隐式指针)阻碍了动态优化,因为要修改的东西太多了,成本也太高了。在这一点上,C语言的显式指针显然不如Java/C#的隐式指针好处理。
相比较而言,传统Basic的动态内存管理现在看来倒成了优点了,真是世事沧桑啊。
我的意思是Profile的开销可以通过某种方法来避免。