程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 托管代碼與非托管代碼的執行效率比較

托管代碼與非托管代碼的執行效率比較

編輯:C#入門知識

一、首先回答一個問題:托管代碼(.net)比非托管代碼(vc++)慢嗎?

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

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

基本上每個人都知道的是,所有.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#代碼的優化設置帶來的影響非常小。 顯而易見的是,

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

 

個人認為C++的編譯(了解c++編譯原理的都知道)在生成中間代碼或匯編代碼過程中,可能涉及到優化處理。優化有兩種:一種優化僅涉及代碼本身,主要是刪除公共表達式、循環優化、代碼外提、無用 代碼賦值等。另一種優化設計具體的計算機硬件,比如,如何根據機器硬件執行指令的特點對指令進行調整優化,減少目標代碼長度,提高執行效率。非托管代碼,這樣帶來的一個不好的地方就是對於不同很多硬件的用戶端,你要達到最好優化效率必須在不同編譯環境編譯不同版本

但是對於c#的來說,JIT編譯則會自動根據硬件的環境去優化編譯IL中間代碼(其實就是匯編代碼)。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved