犀利的小改款:.NET Framework 4.5.1

作者:朱明中 (微軟最有價值專家-MVP)

 

Visual Studio 2013即將於近期內正式發行,距離Visual Studio 2012的發行也才不到一年左右,我們在目前已經發行的Visual Studio 2013 Preview中看到了開發工具有更讓開發人員生產力提升的新功能或強化功能,而只要Visual Studio提升版本時,其核心的.NET Framework一定也會配合升級,不過.NET Framework的更新在這次算是小改款的程度,只將版本號碼提升了Revision的等級,但不代表它改變很少,只是它並沒有像是.NET 4.0或4.5這樣有較大的改變或是全新的功能等等,這次的改版集中在三個層面,包含開發人員生產力 (Developer Productivity)、應用程式執行效能 (Application Performance) 以及持續創新 (Continuous Innovation) 三個部份。

 

開發人員生產力

首先,.NET Framework在開發人員生產力的強化部份,大多數是與Visual Studio更緊密整合的功能,不過有些是來自於Visual Studio的使用者投票投出的重要需求,微軟的開發工具團隊在微軟所設立的Uservoice.com內開放了一個由使用者建議新功能或是改進現有功能的專區,微軟的開發工具團隊成員不定時的檢視這個專區來了解目前Visual Studio和.NET Framework的開發人員會需要哪些新的功能或有哪些潛在的需求。

 

現在Windows作業系統不論是伺服器端或是用戶端的版本,幾乎都包含了64位元的作業系統版本,以期有效的運用CPU和更高容量的記憶體,而在32位元的作業系統中,Visual Studio支援在除錯執行時期修改原始程式碼之後可繼續執行修改過的程式碼的能力,這個能力稱為編輯後繼續 (Edit and Continue) 的功能,讓開發人員能在除錯器中直接修正程式,然後交給除錯器繼續執行,馬上可以看到修改後的成果,對開發人員而言是一個相當實用又具有生產力的功能,然而在升級到64位元的環境後,這個功能並沒有被64位元版本的.NET Framework所支援,如果是在64位元的ASP.NET Web Form或MVC等專案中,若想要在偵錯時期修改程式,一定會看到這個訊息:

 

Visual Studio 2012的64位元不支援編輯後繼續的提示視窗

 

無法在偵錯時期修改程式碼對很多開發人員來說都很不方便,因此這個需求出現在Uservoice.com的Visual Studio專區之後,全球共有2600餘位開發人員投票支持,足見這個功能的重要性。經過長時間的發展後,在Visual Studio 2013/.NET Framework 4.5.1中終於將這個實用的功能實現在64位元的開發環境了。使用Visual Studio 2013 Preview所開啟的ASP.NET專案,在偵錯時期仍然可以編修程式碼,並且即時在偵錯時期生效。

 

不過目前因為仍在Preview階段,故對一些專案仍然會無法順利使用,例如Windows Azure Cloud Service的專案,但未來會擴及任何64位元的平台,像本地的IIS、第三方主機商、Windows Azure Websites或是Windows Azure Virtual Machines都能享有這樣的能力。同時,這個功能在一些特殊的情況無法支援,例如Lambda Expression就不能使用 (這部份則是連x86也不能使用),未來若技術可行時,將會以64位元平台為優先。

 

第二個小改款的更新是在async/await上,async/await讓開發人員在撰寫非同步應用程式時簡化相當多的工作,但是在偵錯的過程中,如果我們要看一些呼叫堆疊資訊 (Call Stack) 時,都會看到很多系統核心的偵錯指令,這是因為async/await會和Task Parallel Library連動的關係,在編譯async/await程式時會產生很多的額外資訊,造成開發人員在瀏覽呼叫堆疊時的困擾:

Visual Studio 2012的呼叫堆疊視窗

 

因此Visual Studio 2013特別將這些額外的資訊隱藏起來,讓呼叫堆疊所產生的資訊能更貼近使用者的程式,而不用讓開發人員看到一大堆的系統層資訊。

 

Visual Studio 2013的呼叫堆疊視窗

 

另外,在Visual Studio針對async/await的工作部份,提供了一個新的工作清單監控視窗,在程式進行很多的await工作時,會顯示目前正在等待以及執行中的工作狀態資訊,包含工作的來源、花費的時間以及程式的位置等,在對Windows Store App這種需利用大量非同步工作的平台來說,可簡化不少在非同步上偵錯的工作,而且這個功能是各類語言 (.NET, C++, JavaScript) 都能共用的。

 

Visual Studio 2013的工作執行狀態視窗

 

第三個值得說明的新功能,是一個很小的實用的功能,以往我們在編寫程式時,如果想要在偵錯器中看到某個函數的回傳值,通常我們會把它放到一個變數內,然後用偵錯器去讀取這個變數的內容,雖然對結果沒有什麼大影響,但就是覺得還要多用一個變數來保存,挺麻煩的。所以就有開發人員在Uservoice.com反應,結果獲得微軟開發工具團隊的認同,並且在Visual Studio 2013中加入了一個能直接看到函數回傳值的功能,這個功能放在除錯器的自動變數視窗中,例如我們編寫了下列程式:

 

static void Main(string[] args)

{

    int i = Func3(Func1(12, 20), 40) + Func2(20, 30);

    Console.WriteLine("Result: {0}", i);

}

 

其中,Func3()的參數來自於Func1(),且Func2()也有自己的回傳值,如果我們想要在偵錯器中看Func3(), Func1()和Func2()的回傳值時,只要在偵錯器內讓它執行之後,就可以在自動變數視窗中看到這三個函數的回傳值了:

 

Visual Studio 2013的自動變數回傳值

 

這樣我們就可以直接以函數的回傳值來驗證程式的結果是否正確。而回傳值有時候不是數值而是物件時,自動變數會很難判斷物件的回傳值內容是否正確,所以Visual Studio 2013也在即時運算視窗中新增了一個$ReturnValue指令,只要在即時運算視窗下這個指令,會得到最後一個函數回傳的值,如果這個值是個物件的話,即會顯示出物件所有的屬性值,你可以比對下圖,變數w是最後一個函數InitWebClient()的回傳值,左邊是自動變數的結果,而右邊則是使用$ReturnValue指令顯示的結果。

Visual Studio 2013的即時運算視窗回傳值與自動變數視窗回傳值的比較

 

第四個功能則是和雲端有關係,如果使用過Windows Azure開發資料庫應用的開發人員應該會很熟悉Windows Azure SQL Database,這個服務是由Windows Azure Platform內的SQL Server大型叢集所建置出的資料庫服務,但因為它對外開放的是資料庫本身,且有時候連線會無故的中斷 (例如閒置過久或是交易時間太長等因素),這時又要重新連線,在.NET Framework 4.5之前,這件事情要由開發人員自己依照ADO.NET的SqlException來判斷並自行重試,重試的演算法也要由開發人員來自訂,所以SQL Database的CAT (Customer Advisory Team) 開發了Transient Fault Framework給Windows Azure的開發人員使用,而.NET Framework 4.5.1則正式將它納入ADO.NET的核心程式碼中。

 

ADO.NET Idle Connection Resiliency這個功能被包裝在Entity Framework 6中,在DbConfiguration設定DbExecutionStrategy物件,Entity Framework 6內建了四種不同的DbExecutionStrategy,分別是:

 

物件

說明

DefaultExecutionStrategy

執行時不包含重試策略,這會自動用於SQL Server以外的資料庫。

DefaultSqlExecutionStrategy

執行時不包含重試策略,但是它會包裝例外狀況,由使用者決定是否要啟用Connection Resiliency。

DbExecutionStrategy

這個物件是所有執行策略的基礎類別,它包裝了指數式重試原則 (exponential retry policy) 演算法,並且由實作來決定要如何使用這個演算法,以及重試的次數等。

SqlAzureExecutionStrategy

專為SQL Database設計的重試策略,會依照已知的可能瞬斷問題進行自動的重試處理。

 

 

第四個功能則與Windows Store Apps有關,在Windows 8開發應用程式時,因為缺少資料流的互動能力,導致很多開發人員都要自己想辦法將資料流轉換成IRandomAccessStream,來獲取資料流與UI介面互動的能力。在.NET Framework 4.5.1中,新增了一個給Stream物件的AsRandomAccessStream()方法,能直接傳回IRandomAccessStream物件,不需要再花時間去做轉換。這個功能可以同時使用在由網路下載的MemoryStream以及由Windows Runtime API中開啟檔案產生的Stream物件。另外,Visual Studio 2013也為不同平台的開發人員做了一些修正,例如當使用C++/CX開發Windows Runtime Component給其他程式使用時,若發生了Exception,在Visual Studio 2012會顯示出訊息,但不會知道這個訊息的原始開發平台為何:

 

在Visual Studio 2012中捕捉來自其他Windows Runtime Component的訊息

 

而在Visual Studio 2013 (.NET Framework 4.5.1)中,我們就能知道這個Windows Runtime Component是用什麼語言開發的:

在Visual Studio 2013中捕捉來自其他Windows Runtime Component的訊息

 

另外在處理跨語言的部份,Visual Studio 2013也做了一些改變,例如針對不同語言使用的型別的轉換,如C#中用的是IList<T>,但C++/CX就要改用IVector<T>的型別,這個能直接在Visual Studio的Intellisense中看到,不必再辛苦的查文件來得到轉換的對照表了。

 

還有幾項針對Windows Store App開發的改變,像是將Nullable數值型別導入到WinRT的結構 (struct) 中,以及在WinRT API中的例外資訊加入了Message與StackTrace等,讓開發人員的除錯更容易。

 

 

應用程式執行效能

.NET Framework 4.5.1在應用程式效能的增強上,分為四個部份。

 

首先是針對ASP.NET應用程式的調整,以往在大型Web Hosting的服務中,雖然一台伺服器能掛載很多的網站,但是並不是所有的網站都是一直保持運作,有些流量不大的網站可能會閒置一段時間之後,由Application Pooling回收,這一回收就會讓應用程式完全釋放,而若要喚起它時,就需要做冷啟動,一般來說冷啟動所花費的時間會很長,尤其是初始化時會做很多工作時,因此配合Windows Server 2012 R2內的IIS,提供了低延遲 (Low-Latency) 與高密度 (High-Density) 的解決方案。Windows Server 2012 R2的IIS會偵測目前所有網站的CPU使用狀況,若是發現有網站一段時間的CPU活動很低時,就會將它移到虛擬記憶體內,但並不會將它釋放,等到有需要處理的連線進來時,就會將這個網站移回記憶體內重新上線提供服務,而這個記憶體搬移的動作不會影響到網站的記憶體資訊,也就是不再需要冷啟動,所以回復的時間很短,按照微軟在實驗室內的測試,使用這個方式可以節省啟動時間達90%,而且可以提升IIS部署網站的密度達7倍。而這個功能必須要執行在Windows Server 2012 R2上才會明顯,且目前Windows Azure Website服務以及Windows Azure Pack Preview內也都內建了這個功能。

 

第二項功能是有關於.NET執行環境內出現的大型物件堆積 (Large Object Heap, LOH),在.NET Framework的標準中,只要佔用記憶體大於85KB的物件即可算是大型物件,一個大型物件堆積會來自於程式中的集合或是陣列等,或是物件本身擁有許多的資料,而堆積在操作時多少會留下一些可用空間,但是依照原本的LOH操作,當GC (Garbage Collector) 來回收資源時,它不會刻意的去壓縮LOH物件,導致LOH內的可用資源無法被釋放,若LOH一多時會造成資源的浪費,因此在.NET Framework 4.5中微軟做了一些嘗試,也收到了不少的正面回應,尤其是在CLR內值的碎裂定址與智慧配置演算法的成功,讓.NET開發團隊踏出了成功的第一步,因此微軟決定將LOH壓縮的功能加到.NET Framework 4.5.1內,不論是由GC自動處理或是由GC.Collect() API來下達的資源回收工作,都能享有LOH壓縮的功能。

 

第三項功能是在多核心平台上執行即時編譯 (Multi-core JIT),將組件動態載入與解析的功能分配給多核心平台的CPU核心上,可提升應用程式在啟動時的效能,就微軟在桌面應用程式上的測試,可提升約16-35%的效能,而在ASP.NET平台上則可以提升15%左右的效能。

 

第四項功能是將.NET Framework更新時所需要的JIT Compilation工作降低,這個改良是針對於Windows Updates時的.NET Framework安全性修補檔的套用,因為每次套用都需要重新編譯整個.NET Framework的程式碼,無形中會消耗許多的時間與電源,尤其是手機或平板的電池消費更是明顯,所以在Windows 8.1中,當.NET Framework更新時,應用程式的效能不會因為.NET Framework更新而受到影響,如此一來也可以提升手機或平板的電池效率與使用時間。

 

持續創新

在持續創新的部份,未來.NET Framework內的功能將會逐漸以核心服務 (Core Services) 為主,基於.NET Framework上的週邊功能,將會大量使用NuGet套件來提供,開發人員只需要使用NuGet即可將週邊功能加到應用程式的參考中,且利用Visual Studio的管理機制,這些週邊套件會和應用程式一併部署到使用者的電腦內,以後就不再需要肥胖的.NET Framework,所以可降低.NET Framework的下載大小,讓.NET Framework更快速的流通。

 

微軟也建立了專屬於.NET Framework功能的.NET Framework Packages NuGet Feed,並內建於Visual Studio 2013的NuGet套件管理員內,它也支援Visual Studio 2010與Visual Studio 2012的NuGet套件管理員,以後想要加入.NET Framework的週邊套件,只要到.NET Framework Packages搜尋即可。

 

 

結語 

在.NET Framework 4.5.1中,雖然並不像.NET Framework 4.0/4.5有很多值得大書特書的新功能,但輕巧貼心的功能強化對開發人員來說可能會遠比提供多數新功能要來得更好,而在不久的將來,Visual Studio 2013與.NET Framework 4.5.1共同發表正式版本時,它們將會帶給開發人員更多不同的體驗。

 

 

參考資料

  1. 1.      https://blogs.msdn.com/b/dotnet/archive/2013/06/26/announcing-the-net-framework-4-5-1-preview.aspx 
  2. 2.      BUILD 2013, 2-303, What’s New in .NET Development課程簡報
  3. 3.      https://entityframework.codeplex.com/wikipage?title=Connection%20Resiliency%20Spec
  4. 4.      https://blogs.msdn.com/b/dotnet/archive/2012/10/18/an-easy-solution-for-improving-app-launch-performance.aspx

 延伸閱讀