C++與C++/CLI的運行速度相比哪個快? C++/CLI和C#的運行速度一樣快?

C++/CLI和C#的運行速度要是一樣,是不是在.net上就沒有必要用C++了?C#多爽啊,F#也行啊。


Native C++跟C++/CLI的應用場景就不一樣,比速度沒意義啊。

從現有實現說那還得是通常Native C++比C++/CLI快。但是很大程度上取決於代碼寫得好不好?寫得不好的native C++如果搬到C++/CLI反而更快,那隻能怪自己代碼沒寫好嗯 &>_,&<

==============================================

從各種資料和我自己的經驗來說,idiomatic C++/CLI比idiomatic C#還是要快一些。

C++/CLI雖然是Managed C++的後繼版本,但兩者用起來感覺是天跟地的差別;前者用起來可以很自然,後者實在是太噁心了嗯。不要把這倆混為一談。

如果要對比C++/CLI與C#的性能,請在x64 CLR上測。原因跟下面要講的相關。

C++/CLI的編譯器跟native C++共用Visual C++編譯器的大部分功能,一直到後端最後的代碼生成才最不同。中間的優化部分略有不同,但比較多的優化應該還是共用的。C++/CLI版後端生成MSIL,native C++版後端生成native code。Visual C++編譯器是真正的優化編譯器,而Visual C#的編譯器(csc)只會做一些非常簡單的優化,在MSIL層面上兩者的優化程度有所不同。這部分差異主要不是來自語言/語義,而是來自編譯器的實現。

C++/CLI仍然支持裸指針操作和裸內存訪問,也算是idiomatic C++/CLI,這部分對應生成的MSIL是idiomatic C#代碼所不會生成的(大家不會隨便在C#里寫unsafe來訪問裸指針/裸內存),由此會產生一些性能差異。這部分差異是語言的慣用法帶來的。

以前C++/CLI編譯器組的人發現過奇怪的現象:在32位x86的CLR上,C++/CLI一開始生成的代碼反而比C#的還慢。後來發現是因為x86的CLR的JIT編譯器(JIT32)的內聯以及其它一些代碼生成的優化選擇比較弱,如果要JIT編譯的方法太大的話JIT32反而會減弱對其的優化程度。這對JIT32來說是個合理的取捨——它作為一個Client編譯器,目標是編譯速度快、代碼質量一般就行。所以在做優化時它會特別小心,儘可能不用複雜度高的演算法去優化。而要編譯的方法大小就是影響JIT32選擇優化演算法的一個因素,足夠小的話就可以容忍更高複雜度的優化演算法,而方法太大就只能用複雜度低的演算法。C++/CLI的編譯器一開始用跟native C++基本一樣的優化策略,會做激進內聯,結果生成的代碼對JIT32來說有可能太大反而不利優化。

結果就是C++/CLI的編譯器為了遷就JIT32要降低內聯的激進性;可能其它一些優化也有類似的狀況要減弱的。所以這不是測試C++/CLI真正性能的好場景。

在x64上則不一樣。在RyuJIT之前,x64的CLR的JIT編譯器是JIT64,其後端源自Visual C++的編譯器後端UTC,會嘗試做比JIT32的更耗時、更激進的優化。這種條件下C++/CLI的表現會更好一些。


《CLR via C#》第一章《CLR的執行模型》就說了託管代碼和非託管代碼的問題:

雖然你可能很難相信,但許多人(包括我)都認為託管應用程序的性能實際上超越了非託管應用程序。有許多原因使我們相信。例如,當JIT編譯器在運行時將IL代碼編譯成本機代碼時,編譯器對執行環境的認識比非託管編譯器更深刻。下面例舉了託管代碼相較於非託管代碼的優勢。

  • JIT編譯器能判斷應用程序是否運行在Intel Pentium 4 CPU上,並生成相應的本機代碼來利用Pentium 4支持的任何特殊指令。相反,非託管應用程序通常是針對具有最小功能集合的CPU編譯的,不會使用能提升性能的特殊指令。
  • JIT編譯器能判斷一個特定的測試在它運行的機器上是否總是失敗。例如,假定一個方法包含以下代碼:if (numberOfCPUs &> 1) { ... } 如果主機只有一個CPU,JIT編譯器不會為上述代碼生成任何CPU指令。在這種情況下,本機代碼將針對主機進行優化,最終代碼變得更小,執行得更快。

  • 應用程序運行時,CLR可以評估代碼的執行,並將IL重新編譯成本機代碼。重新編譯的代碼可以重新組織,根據剛才觀察到的執行模式,減少不正確的分支預測。雖然目前版本的CLR還不能做到這一點,但將來的版本也許就可以了。

除了這些理由,還有另一些理由使我們相信未來的託管代碼在執行效率上會比當前的非託管代碼更優秀。大多數託管應用程序目前的性能已相當不錯,將來還有望進一步提升。

如果試驗表明,CLR的JIT編譯器似乎沒有是自己的應用程序達到應有的性能,那麼為了進一步確認,還應該使用.NET Framework SDK配套提供的NGen.exe工具。該工具將程序集的所有IL代碼編譯成本機代碼,並將這些本機代碼保存到一個磁碟文件中。在運行時載入程序集時,CLR自動判斷是否存在該程序集的預編譯版本。如果是,CLR就載入編譯代碼。這樣一來,就避免了在運行時進行編譯。注意,NGen.exe對最終執行環境的預設是很保守的(不得不如此)。所以,NGen.exe生成的代碼不會像JIT編譯器生成的代碼那樣進行高度優化。

另外可以考慮使用System.Runtime.ProfileOptimization類。該類導致CLR檢查程序運行時哪些方法被JIT編譯,結果被記錄到一個文件。程序再次啟動時,如果是在多CPU機器上運行,就用其他線程並發編譯這些方法。這是應用程序運行得更快,因為多個方法並發編譯,而且是在應用程序初始化時編譯,而不是在用戶和程序交互時才「即時」編譯。

簡而言之就是如果你自己的C艹技術沒有 @vczh 那樣厲害,那麼你寫的非託管代碼可能比託管的代碼速度更慢...


如果你不使用new操作符(包括malloc等),那當然是C++快了。如果你頻繁使用了new操作符,哪個快很嚴重的依賴與你的水平與Jeff Dean的差距,差距越大,CLI越快。


你指的是C++/CLI 吧?

C++/CLI 用途在於可以在.net很方便重用已有的c++代碼。

和速度沒啥關係。如果你的C++/CLI 100% 調用.net的api。 也不會快到哪裡去。


推薦閱讀:

Node.js和.Net 4.5下的await、async相比有什麼不同?
如何提升ASP.NET網站首次打開速度?
.NET 下的性能問題如何定位?
自學編程十年,依然沒有編寫出過什麼有用的東西,想知道下一步怎麼走?
如何使一個變數的名稱等於另一個變數的值?-.net?

TAG:編程 | 計算機 | NET | C | C# |