之前常聽說C#和Java與C++的速度接近,更有甚者說很多情況下他們都比C++快,而且舉出一大堆的范例(多是些IO操作,測量誤差超級大,因此很難令人信服),于是聽到很多人出來圓場,說對于語言內建類型(整形、浮點型等),編譯成二進制應該相差不大,這似乎有些道理,但我仍然有些懷疑。

還曾經聽不少人鼓吹過腳本,說腳本程序比C++程序慢不了多少,有人甚至給10%,對此我不加評論了,看看這里的測試結果就一目了然。

下面有個浮點密集型的計算程序,沒有使用blitz++和MTL,很符合一般性應用,如果用上他們那就不好說怎么樣,因為主要是和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秒的測試(Ruby4000秒以外,不予顯 )

Test

Time(sec)

Relative time

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++/CLIC#的可執行文件后,可以發現,程序的熱點函數 Sphere.Intersect()在兩個版本中,C++/CLI版本的代碼大小(code size)201字節, C#則為125字節! C++/CLI版本在編譯時,已把函數內所有Vec類的方法調用全部內聯,而C#版本則使用callvirt調用Vec的方法。估計JIT沒有把這函數進 行內聯,做成這個性能差異。另外,C++/CLI版本使用了值類型,并使用指針(代碼中為引用)托管代碼(C++/CLI)的渲染時間,僅為原生非括管代碼(IC++)1.91倍,個人覺得.NetJIT已經非常不錯。

另一方面,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),對于4Hyper Threading來說算是不錯的結果。讀者若有興趣,也可以自行測試C# 4.0的并行新特性。

動態語言組別

首先,要說一句,Google太強了,難以想像JsChome的渲染時間僅是IC++16.12倍,C#4.94倍。

以下比較各動態語言的相對時間,以JsChrome為基準。 ChromeV8 JavaScript引擎(1.00x)大幅拋離FirefoxSpiderMonkey引擎(15.09x)。而LuaJIT(3.49x)Lua(5.16x)則排第二和第三名。 LuaJIT版本是沒有JIT68%,并沒有想像中的快,但是也比Python(16.48x)快得多。曾聽說過Ruby有效能問題,沒想到問題竟然如此嚴重(327.31x),其渲染時間差不多是Python20倍.