回 帖 发 新 帖 刷新版面

主题:C#, Java, 脚本似乎远没有吹嘘的那么快。

之前常听说C#和Java与C++的速度接近,更有甚者说很多情况下他们都比C++快,而且举出一大堆的范例(多是些IO操作,测量误差超级大,因此很难 令人信服),后来听到很多人出来圆场,说对于语言内建类型(整形、浮点型等),编译成二进制应该相差不大,这似乎有些道理,但我仍然有些怀疑。

还曾经听不少人鼓吹过脚本,说脚本程序比C++程序慢不了多少,有人甚至给出慢10%左右,对此我不加评论了,看看这里的测试结果就一目了然。

下面有个浮点密集型的渲染程序,没有使用blitz++和MTL这样的大块头,很符合一般性应用场合,如果用上他们那就不好说怎么样了,因为C++和Fortran比科学计算速度时才用宰牛刀。下面已经有人编码测试了。

只讲速度,如果再比内存,其他几种语言就没有必要比下去了,虚拟机吃内存很多,脚本更是疯狂吃内存。

不同语言版本的代码到原作者提供的地址去下载:http://files.cnblogs.com/miloyip/smallpt20100623.zip

下面是测试用的系统配置:
测试配置
•    硬件: Intel Core i7 920@2.67Ghz(4 core, HyperThread), 12GB RAM
•    操作系统: Microsoft Windows 7 64-bit
测试名称     编译器/解译器     编译/运行选项 
VC++          Visual C++ 2008 (32-bit)     /Ox /Ob2 /Oi /Ot /GL /FD /MD /GS- /Gy /arch:SSE /fp:fast 
VC++_OpenMP   Visual C++ 2008 (32-bit)     /Ox /Ob2 /Oi /Ot /GL /FD /MD /GS- /Gy /arch:SSE /fp:fast /openmp 
IC++          Intel C++ Compiler (32-bit)     /Ox /Og /Ob2 /Oi /Ot /Qipo /GA /MD /GS- /Gy /arch:SSE2 /fp:fast /Zi /QxHost 
IC++_OpenMP   Intel C++ Compiler (32-bit)     /Ox /Og /Ob2 /Oi /Ot /Qipo /GA /MD /GS- /Gy /arch:SSE2 /fp:fast /Zi /QxHost /Qopenmp 
GCC           GCC 4.3.4 in Cygwin (32-bit)     -O3 -march=native -ffast-math 
GCC_OpenMP    GCC 4.3.4 in Cygwin (32-bit)     -O3 -march=native -ffast-math -fopenmp 
C++/CLI       Visual C++ 2008 (32-bit), .Net Framework 3.5     /Ox /Ob2 /Oi /Ot /GL /FD /MD /GS- /fp:fast /Zi /clr /TP 
C++/CLI_OpenMP  Visual C++ 2008 (32-bit), .Net Framework 3.5     /Ox /Ob2 /Oi /Ot /GL /FD /MD /GS- /fp:fast /Zi /clr /TP /openmp 
C#             Visual C# 2008 (32-bit), .Net Framework 3.5      
*C#_outref     Visual C# 2008 (32-bit), .Net Framework 3.5      
F#             F# 2.0 (32-bit), .Net Framework 3.5      
Java           Java SE 1.6.0_17     -server 
JsChrome       Chrome 5.0.375.86      
JsFirefox      Firefox 3.6      
LuaJIT         LuaJIT 2.0.0-beta4 (32-bit)      
Lua            LuaJIT (32-bit)     -joff 
Python         Python 3.1.2 (32-bit)      
*IronPython    IronPython 2.6 for .Net 4      
*Jython        Jython 2.5.1      
Ruby           Ruby 1.9.1p378      
渲染的解像度为256x256,每象素作100次采样。
结果及分析
下表中预设的相对时间以最快的单线程测试(IC++)作基准,用鼠标按列可改变基准。由于Ruby运行时间太长,只每象素作4次采样,把时间乘上25。另 外,因为各测试的渲染时间相差很远,所以用了两个棒形图去显示数据,分别显示时间少于4000秒和少于60秒的测试(Ruby是4000秒以外,不予显 示)。 
Test;               Time(sec);    Relative times;
IC++_OpenMP         2.861         0.19x
VC++_OpenMP         3.140         0.21x
GCC_OpenMP          3.359         0.23x
C++/CLI_OpenMP      5.147         0.35x
IC++                14.761        1.00x
VC++                17.632        1.19x
GCC                 19.500        1.32x
C++/CLI             27.634        1.87x
Java                30.527        2.07x
C#_outref           44.220        3.00x
F#                  47.172        3.20x
C#                  48.194        3.26x
JsChrome            237.880       16.12x
LuaJIT              829.777       56.21x
Lua                 1,227.656     83.17x
IronPython          2,921.573     197.93x
JsFirefox           3,588.778     243.13x
Python              3,920.556     265.60x
Jython              6,211.550     420.81x
Ruby                77,859.653    5,274.69x
C++/.Net/Java组别
静态语言和动态语言在此测试下的性能不在同一数量级。先比较静态语言。
C++和.Net的测试结果和上一篇博文相若,而C#和F#无显著区别。但是,C++/CLI虽然同样产生IL,于括管的.Net平台上执行,其渲染时间 却只是C#/F#的55%左右。为什么呢?使用ildasm去反汇编C++/CLI和C#的可执行文件后,可以发现,程序的热点函数 Sphere.Intersect()在两个版本中,C++/CLI版本的代码大小(code size)为201字节, C#则为125字节! C++/CLI版本在编译时,已把函数内所有Vec类的方法调用全部内联,而C#版本则使用callvirt调用Vec的方法。估计JIT没有把这函数进 行内联,做成这个性能差异。另外,C++/CLI版本使用了值类型,并使用指针(代码中为引用)托管代码(C++/CLI)的渲染时间,仅为原生非括管代码(IC++)的1.91倍,个人觉得.Net的JIT已经非常不错。 
另一方面,Java的性能表现非常突出,只比C++/CLI稍慢一点,Java版本的渲染时间为C#/F#的65%左右。以前一直认为,C#不少设计会使其性能高于Java,例如C#的方法预设为非虚,Java则预设为虚;又例如C#支持struct作值类型(value type),Java则只有class引用类型(reference type),后者必须使用GC。但是,这个测试显示,Java VM应该在JIT中做了大量优化,估计也应用了内联,才能使其性能逼近C++/CLI。 
纯C++方面,Intel C++编译器最快,Visual C++慢一点点(1.19x),GCC再慢一点点(1.32x)。这结果符合本人预期。 Intel C++的OpenMP版本和单线程比较,达5.16加速比(speedup),对于4核Hyper Threading来说算是不错的结果。读者若有兴趣,也可以自行测试C# 4.0的并行新特性。 
动态语言组别
首先,要说一句,Google太强了,难以想像JsChome的渲染时间仅是IC++的16.12倍,C#的4.94倍。 
以下比较各动态语言的相对时间,以JsChrome为基准。 Chrome的V8 JavaScript引擎(1.00x)大幅抛离Firefox的SpiderMonkey引擎(15.09x)。而LuaJIT(3.49x)和Lua(5.16x)则排第二和第三名。 Lua的JIT版本是没有JIT的68%,并没有想像中的快,但是也比Python(16.48x)快得多。曾听说过Ruby有效能问题,没想到问题竟然如此严重(327.31x),其渲染时间差不多是Python的20倍.

回复列表 (共4个回复)

沙发

对这个测试所使用的硬件表示流口水~
源代码下载地址:http://files.cnblogs.com/miloyip/smallpt20100623.zip,这个需要输入用户名密码,暂时没有去看了。
听说IC++的选项,如果用SSE4会比SSE2快很多,不知道楼主有没有试试。

IC++/VC++/G++,这个我以前也测试了一下。我使用的是整数,测试手段也是业余级别,不过结论倒是是一致的。
我原来一直以为javascript是很慢的语言,没想到google让它比luaJIT还快了若干倍。这个结果让我吓了一跳。
Java和C#的表现,我觉得倒是在情理之中。尽管有很多理论让人认为JIT比直接编译更快,但最终事实胜于雄辩,C++还是要快一些。我对JIT不怎么了解,不知道它是否还有潜力可挖,也许还有一些上升空间也未为可知。
我用IE9(beta版),windows 7 home basic, i7 1.6G,测试结果为981.875秒。中途因为停止响应,鼠标到处点,如果安分一些的话,可能会稍微更快一点。这样看来IE9的性能也还算很不错了。

板凳

测试系统的硬件嘛,呵呵,是配置很高啊。不过可不是我测试的啊,代码也不是我写的。我用的电脑就2.83GHz的CPU4核,内存3GB,Windows XP SP3,这是班上的。家用的配置更低,太原始了,属于骨灰级别的。

3 楼

我觉得应该用AMD的处理器测试一下比较公平,毕竟英特尔的编译器对于自己的CPU应该是有偏袒的。还有就是Linux系统上也应该测一下,毕竟Visual Studio对于Windows还有有点偏爱的。放在Linux上,如果用AMD的处理器,未必能胜过gcc的编译优化能力。

出乎我预料的是C#居然比Java慢,慢就慢吧居然在WIN上比Java慢,是不是有点说不过去呀。听说Oracle和IBM合作将致力于开源JDK部分的开发,我看C#要想拼过Java越来越难了。

我也一直认为脚本中Lua应该快一些,毕竟它为嵌入式准备的,结果唉,还算说得过去吧。

4 楼

十倍以下,不同语言和平台,谈不上谁比谁快,优化重点不同。
脚本速度约是编译语言的1/10到1/100都正常。

我来回复

您尚未登录,请登录后再回复。点此登录或注册