.NET 5 中的隱藏特性,很多人還不知道!
轉(zhuǎn)自:hez2010 cnblogs.com/hez2010/p/13963803.html
前言
雙十一當(dāng)天,個(gè)人覺得非常香,并且花了 10 分鐘時(shí)間就把自己的 4 個(gè) .NET Core 3.1 的項(xiàng)目升級(jí)到了 .NET 5,堪稱無痛。
但是,.NET 5 中還有一些沒有正式公開的隱藏特性,那么現(xiàn)在就開始介紹吧。
Crossgen 2
Crossgen 其實(shí)就是眾所周知的 ReadyToRun 特性。該功能將你的程序集進(jìn)行一定程度的 AOT 編譯,然后在運(yùn)行時(shí)跟蹤熱路徑對(duì)一些方法進(jìn)行帶有更多優(yōu)化的 JIT 編譯,即分層編譯,這使得程序集的加載速度大幅提高。
但是 .NET 5 其實(shí)帶了 Crossgen 的下一個(gè)版本:Crossgen 2。
Crossgen 2 的代碼幾乎是從 CoreRT 繼承而來,并在此基礎(chǔ)上做了很大改進(jìn)。CoreRT 可以對(duì) .NET 程序集進(jìn)行完全的原生優(yōu)化編譯,編譯出來的東西就是完全 native 的,和 Go 的體驗(yàn)完全一致。
Crossgen 2 則使用了這套方法,將你的程序集在支持范圍之內(nèi)進(jìn)行 Native AOT 編譯,然后運(yùn)行時(shí)直接加載啟動(dòng),并根據(jù)運(yùn)行情況再使用 JIT 編譯器進(jìn)行進(jìn)一步的優(yōu)化,是一種混合 AOT 策略。
為什么說在支持范圍之內(nèi)呢?因?yàn)?Native AOT 必然對(duì)動(dòng)態(tài)加載和 Emit 等特性不友好,但是 Crossgen 2 對(duì)于這些地方則直接跳過,并且由于是混合 AOT 方案,運(yùn)行時(shí)依然存留有 JIT,因此這些功能完全不會(huì)受到影響。
使用
使用方法很簡單,在你發(fā)布程序的時(shí)候加命令行參數(shù) /p:PublishReadyToRun=true /p:PublishReadyToRunUseCrossgen2=true 即可,例如:
dotnet publish -c Release -r win-x64 /p:PublishReadyToRun=true
/p:PublishReadyToRunUseCrossgen2=true注意
由于該功能尚未正式發(fā)布,并且存在一些已知的問題還沒有解決,因此如果要使用的話建議對(duì)發(fā)布出的程序做好測(cè)試。
另外,.NET 6 將會(huì)用 Crossgen 2 代替現(xiàn)有的 Crossgen 1,追求穩(wěn)定的話可以等到明年再用。
棧上替換
棧上替換,即 On Stack Replacement。這個(gè)特性允許在運(yùn)行時(shí),即使一個(gè)方法有活躍的棧幀也能直接替換實(shí)現(xiàn)。
因此對(duì)于分層 JIT 功能來說,這個(gè)特性就允許 JIT 將未經(jīng)優(yōu)化的代碼直接切換成經(jīng)過優(yōu)化的代碼,即使被切換的方法存在活躍棧幀也沒問題。
使用
這是一個(gè)運(yùn)行時(shí)特性,需要通過設(shè)置兩個(gè)環(huán)境變量來開啟:
bash:
export COMPlus_TC_QuickJitForLoops=1
export COMPlus_TC_OnStackReplacement=1cmd:
set COMPlus_TC_QuickJitForLoops=1
set COMPlus_TC_OnStackReplacement=1pwsh:
$env:COMPlus_TC_QuickJitForLoops = 1
$env:COMPlus_TC_OnStackReplacement = 1注意
當(dāng)前僅支持 x64,且目前處于實(shí)驗(yàn)性階段。
更激進(jìn)的發(fā)布裁剪
發(fā)布裁剪可以在發(fā)布時(shí)將沒有用到的代碼裁剪掉,使得發(fā)布出去的程序體積大幅度減小。
但是 .NET 5 默認(rèn)的裁剪行為是程序集粒度的,意味著會(huì)保留用到了的程序集,哪怕你只用了程序集中的一個(gè)方法,整個(gè)程序集也會(huì)被保留下來。
但是 .NET 5 提供了一種更為激進(jìn)的裁剪方式,基于方法粒度進(jìn)行裁剪。
開啟這個(gè)特性之后,如果一個(gè)程序集只被調(diào)用了一個(gè)方法,那裁剪后將只會(huì)保留這一個(gè)方法,而不是保留整個(gè)程序集。
使用
使用方法很簡單,只需要發(fā)布時(shí)附帶命令行參數(shù) /p:PublishTrimmed=true /p:TrimMode=Link 即可,例如:
dotnet publish -c Release -r win-x64 /p:PublishTrimmed=true /p:TrimMode=Link如果因?yàn)閯?dòng)態(tài)加載需要保留一些方法、類型或者程序集的話,可以按照如下文章內(nèi)的方法進(jìn)行配置:
https://devblogs.microsoft.com/dotnet/customizing-trimming-in-net-core-5/
注意
由于這種方法較為激進(jìn),請(qǐng)確保發(fā)布后進(jìn)行充分的測(cè)試,以免出現(xiàn)因?yàn)閯?dòng)態(tài)加載導(dǎo)致運(yùn)行時(shí)找不到方法的問題。
實(shí)驗(yàn)性運(yùn)行時(shí)
.NET 大量的新功能已經(jīng)轉(zhuǎn)移到專門的實(shí)驗(yàn)性運(yùn)行時(shí)倉庫進(jìn)行開發(fā)了,例如:
NativeAOT:基于 RyuJIT 的完全原生編譯
NativeAOT-LLVM:使用 LLVM 做代碼生成的完全原生編譯
ManagedQuic:完全 C# 實(shí)現(xiàn)的 QUIC 協(xié)議
Utf8String:UTF-8 字符串類型
JsonCodeGen:使用代碼生成器的 JSON
s390x:.NET 在 s390x 架構(gòu)的移植
FreeBSD:.NET 在 FreeBSD 系統(tǒng)的移植
MIPS64:.NET 在 MIPS64 架構(gòu)的移植
RegexSRM:基于微軟研究院成果 Symbolic Regex Matcher 的正則表達(dá)式實(shí)現(xiàn)
DllImportGenerator:用于自動(dòng)生成 P/Invoke 接口的代碼生成器
歡迎前往實(shí)驗(yàn)倉庫中對(duì)應(yīng)分支進(jìn)行試用和貢獻(xiàn)代碼:https://github.com/dotnet/runtimelab 。
另外,MIPS64 的移植工作由國內(nèi)龍芯社區(qū)團(tuán)隊(duì)完成,并將在 .NET 6 并入官方主線,相關(guān)信息在 https://github.com/gsvm/loongson-dotnet 。
總結(jié)
.NET 5 有很多的沒有公開宣布的特性,其中很多特性都非常棒,雖然沒有正式發(fā)布的現(xiàn)階段可能還存在一些問題,后期也可能會(huì)有較大的改動(dòng),但是感興趣的讀者不妨提前體驗(yàn)一波。


再見Vip,免費(fèi)看網(wǎng)飛影視大片!

副業(yè)剛需:這個(gè)開源小程序外賣紅包項(xiàng)目,有人月入5000+!
