託管程式碼(.net)比非託管程式碼(vc++)慢嗎?

iDotNetSpace發表於2009-01-04

如果你用上面這個問題去問每一個人,基本上每個人都會回答,肯定會慢! 那麼他們說的是正確的嗎? 不,並不正確。 問題在於,絕大多數人認為.Net只是一個基於執行庫的框架,就像Java或者VB,或者他們甚至以為.Net使用像Java一樣的虛擬機器系統。 他們並沒考慮到程式本身,沒考慮到程式是用來幹什麼,也沒有考慮到訪問網路或者磁碟的速度因素。簡單來說,就是他們根本沒有思考!

.NET並不像那種執行庫(VB或者Java)。 它是一個經過精心構思的,並且微軟在其身上下了極大功夫的框架,以保證它的良好執行。 在這篇文章 我將給大家展示一些將需要大量運算的程式碼,並且將他編譯成託管以及非託管程式碼。 然後我將測量這兩個庫分別的表現。 你將看到, 並不會因為這是.net程式就自動要比c++程式慢,事實是,在某些情況,託管程式碼甚至比非託管程式碼更快。

題外話(我自己補充的,原文沒有提到):
.NET的執行機制,由於本人現在研究的專案跟.Net庫底層有些關係,所以多少了解一些,現在簡單給大家介紹一下。
基本上每個人都知道的是,所有.Net語言都將被編譯成為一個叫做IL彙編的中間語言。但是計算機是如何執行這個中間程式碼的,卻是很多人不知道,甚至理解錯誤了的。
JIT是.NET程式執行的重要部件之一,全稱是即時編譯器。我剛才說的誤解,就是很多人(絕對不是少數,問了很多c++程式設計師,10個有9個這種想法)都以為JIT其實就是跟Java VM差不多的東西,是一個Interpreter,在執行時讀取IL彙編程式碼,然後模擬成x86程式碼(也就是俗稱的虛擬機器)。但是事實上,.NET使用的是更為高階的技術。 .Net程式被載入入記憶體以後,當某段IL程式碼被第一次執行的時候,JIT編譯器就會將這段IL程式碼,全部編譯成原生程式碼,然後再執行。這也就是為什麼.NET程式第一次執行都啟動很慢的原因! 隨.NET庫,微軟還附帶了一個工具,可以事先將.NET程式所有的IL程式碼都編譯成原生程式碼並儲存在快取區中,這樣一來,這個程式就跟c++編譯的一模一樣了,沒有任何區別,執行時也可以脫離JIT了(這裡不要混淆了,這裡不是說可以脫離.NET庫,而是說不需要在進行即時編譯這個過程了)。所以,請不要將.NET和Java混為一談,兩個的執行效率根本不是一個等級的!

作為測試演算法,我們選中了FFT(Fast Fourier Transform),這是一個將跟時間有關係的資料(例如音樂)轉換成他應有的頻率資訊的演算法。
這個演算法有很多種,如果你用Google搜尋會發現很多,這裡我選中了Real Discrete Fourier Transform, 因為他比較簡單明瞭,比較好修改。 我將其複製了4份,分別用於測試託管的C++, C++/CLI,C#。

非託管的程式碼我只是將其函式名稱改成了fourier,並且加入了__declspec(dllexport)用來匯出。
託管的程式碼改動的要稍多些:

    * 方法引數改成了託管的Array, 並且使用Array::Length來代替額外的長度引數
    * 涉及到三角函式的地方都改為使用Math類下的方法
    * 演算法被作為一個公開類的靜態成員匯出

然後我把託管的c++程式碼轉換成了c#,只做了極小的變化(大多數是語法上以及申明上的改動)
最後,我又將託管的c++程式碼轉換成了C++/CLI

然後我們將所有版本都分別編譯幾個不同的版本:未優化版,空間優化,速度優化.

結果:
我將這些程式分別在兩臺電腦上進行了測試,一臺是裝了.net 2.0的 XPSP2,處理器是PIII 850, 512MB記憶體。 另外一臺是Vista build 5321,處理器是2GHz 移動PIV,1G記憶體,每次測試我都是取100次演算法運算的平均值,結果單位是毫秒,以下是PIII電腦的執行結果:
            沒優化   進行了空間優化  進行了速度優化
Unmanaged  92.88 ± 0.09  88.23 ± 0.09  68.48 ± 0.03
Managed C++  72.89 ± 0.03  72.26 ± 0.04  71.35 ± 0.06
C++/CLI  73.00 ± 0.05  72.32 ± 0.03  71.44 ± 0.04
C# Managed  72.21 ± 0.04  69.97 ± 0.08

PIV電腦的結果:
            沒優化   進行了空間優化  進行了速度優化
Unmanaged  45.2 ± 0.1  30.04 ± 0.04  23.06 ± 0.04
Managed C++  23.5 ± 0.1  23.17 ± 0.08  23.36 ± 0.07
C++/CLI  23.5 ± 0.1  23.11 ± 0.07  23.80 ± 0.05
C# Managed  23.7 ± 0.1  22.78 ± 0.03

可以看出,非託管程式碼在不同的優化方案上存在很大的效率差異,PIII上不優化比優化慢35%,在PIV上也是。 在這個簡陋的統計上表明,不管是哪種優化方案,管理程式碼在執行效率上並沒有太大區別,編譯器和聯結器並沒有影響到執行效率太多, 我在後面會說更多關於這方面的資訊。
奇怪的是,在Vista下,管理程式碼進行空間優化甚至比進行速度優化速度更快!

C#的結果跟託管的C++比起來,並沒有太大區別,但是可以看到, 優化過的c#程式碼比優化過的託管C++程式碼要稍快些

現在來比較以下託管程式碼和非託管程式碼的結果。 在不優化的情況下,託管程式碼遠遠快於非託管程式碼,這個差距在優化空間後被稍微縮短了點,只有在進行速度優化後,非託管程式碼才比託管程式碼稍稍快上一點
非託管程式碼和C#程式碼的差別只有3%左右,不過,c#程式碼仍然比c++的更快!

.NET的編譯器(在這個情況下是託管的C++程式碼) 可以看成是與非託管C++編譯器的Parser引擎是等價的。編譯器將生成類,方法等的表,然後進行了一系列的高等級優化。 .NET真正的非託管編譯器其實是JIT(即時編譯器):這才是程式真正轉換成低等級的x86程式碼的地方..NET編譯器和JIT編譯的組合,其實跟非託管C++編譯器等價的,唯一的不同是,.Net被分成了兩個部分.事實上,JIT在執行託管程式碼時,對.NET程式針對客戶電腦進行了優化,而不是像非託管程式碼那樣是在程式設計師電腦上進行的優化。結果表明,託管C++程式碼和c#程式碼的優化設定帶來的影響非常小。 顯而易見的是,C#程式碼至少是跟C++程式碼同樣高效。

記住! 在.NET中沒有任何一個部分是自動就必C++程式碼慢的,執行效率完全取決於程式設計師。任何一個告訴你託管程式碼比非託管程式碼慢的人,都是沒有考慮到.NET執行機制的人,簡單的說,就是對.NET一竅不通!

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-526495/,如需轉載,請註明出處,否則將追究法律責任。

相關文章