在.net中為什么第一次執行會慢?


眾所周知.NET在第一次執行的時比第二第三次的效率要低很多,最常見的就是ASP.NET中請求第一個頁面的時候要等上一段時間,而后面任意刷新響應都非常迅速,那么是什么原因導致的呢?為什么微軟不解決這個問題呢?

問題

首先大家可以在心底回答這幾個問題,這也是讀完本文之后會陸續解決的問題。

1.生成就是編譯嗎?

2.既然執行過一次之后效率會高很多為什么微軟不解決這樣的問題呢?

3.預編譯比JITCompiler的方式好嗎?

效率比較

image

第一次執行耗費了399

第二次執行耗費了5

為什么差這么多呢?后面就讓我們來揭曉。

注:單位不是ms(毫秒)

生成就是編譯嗎?

首先我先回答第一個問題:生成也是編譯(語言編譯),只不過不是編譯成機器碼(匯編),而是“IL”,但一般人會聽到編譯都聯想到編譯成機器碼(匯編),所以大家最好叫生成。

既然在生成的時候沒有編譯成機器碼,那么計算機是如何執行的呢?下面我們來看描述了方法首次調用的一幅圖,摘自網絡。

 

image

可以看出,在WriteLine下有個JITCompiler,沒錯就是這個函數幫我們把WriteLine編譯成了機器碼。

那當第二次執行的時候JITCompiler會變成本地代碼,也就是說JITCompiler不會再次執行了,順帶得到的好處就是效率提升了。

既然執行過一次之后效率會高很多為什么微軟不解決這樣的問題呢?

為什么微軟不再VS生成的時候就編譯成機器碼呢?

其實微軟有提供相關的設置(預編譯),但不推薦使用。

微軟既然提供了預編譯為什么不把它設為默認的呢?

這個就得跳到第三個問題咯,大家繼續往下看。

預編譯比默認的方式好嗎?

多平台支持

再寫完一個程序時(WinForm比較常見)可以發現可疑同時運行在x86和x64的平台上,那為什么x64的操作系統一開始會有那么多的x86軟件兼容問題呢?

image

其實針對x86和x64平台的指令是有區別的,深入的我也不太了解,有大牛可以細說說。

那為什么一次生成可以同時在x64和x86上同時運行呢?

原因其實很簡單:JITCompiler是在執行方法時才會將IL編譯成機器碼,那么微軟當然有辦法根據平台的差異性編譯出對應的機器碼。

忽略不適應代碼

   1: if (numberOfCPUs > 1) {
   2: ...
   3: }

如果主機只有一個CPU,JIT編譯器不會為上述代碼生成任何CPU指令,那么這樣順帶的結果就是最終的代碼變得更小,執行的更快(可能有人說扯淡,就算一個CPU的這段代碼也不會執行啊,那么大家得考慮機器碼不是面向對象的語言可能一個小小的if就會順帶很多指令)。

未來還有更多

這種優化未來只會更多,因為CLR在不停的更新。。。

拋棄預編譯嗎?

答案肯定是否的,預編譯有自己的優勢,如果你所寫的代碼只在一台服務器或者少個數的服務器上運行,那么完全可以針對服務器進行預編譯,但面向多服務端、客戶端的程序還是最好采用JIT編譯。

 

結語

部分引自:CLR via C#(第三版)

其實我覺得.NET並不是完全的編譯型語言,從JIT編譯來看他也是一種解析執行語言(把IL解析成機器語言)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM