兼容 .NET Core3.0, Natasha 框架实现 隔离域与热编译操作
關(guān)于 Natasha
???動態(tài)構(gòu)建已經(jīng)成為了封裝者們的家常便飯,從現(xiàn)有的開發(fā)趨勢來看,普通反射性能之低,會迫使開發(fā)者轉(zhuǎn)向EMIT/表達(dá)式樹等構(gòu)建方式,但是無論是EMIT還是表達(dá)式樹,都會依賴于反射的元數(shù)據(jù)。
Natasha 通過使用 Roslyn技術(shù),已經(jīng)解決了上述的問題,在保證高效可靠的同時,提供了一條相對完整的動態(tài)編譯鏈,以C#語法輕松構(gòu)建動態(tài)代碼,學(xué)習(xí)成本很低,排查以及維護(hù)方面有正確友好的異常輸出。為此以Roslyn相關(guān)模塊功能為基礎(chǔ),封裝了Natasha, Natasha使用友好的API和層級分明的模板,極大的提升了開發(fā)者構(gòu)建動態(tài)代碼的體驗,讓事情變得更簡單,人人都可以低成本構(gòu)建動態(tài)代碼,人人都可以定制自己喜愛的動態(tài)功能。
文章內(nèi)容未經(jīng)許可,禁止轉(zhuǎn)載!
Natasha 屬于 NCC(.NET Core Community) 成員項目。
項目倉庫:https://github.com/dotnetcore/Natasha
一、 2.0預(yù)覽版本增加了哪些功能
大部分為底層的升級優(yōu)化,例如:
引擎兼容 Core3.0
優(yōu)化編譯流程,增加編譯前語法檢測及日志,統(tǒng)一采用流加載方式
在 Vito 的建議下改進(jìn)了日志目錄及命名
ALC 同類覆蓋編譯
支持域的創(chuàng)建、卸載、鎖操作
支持共享域與獨立域協(xié)作
支持獨立域的程序集創(chuàng)建、覆蓋操作
支持插件及依賴的加載
構(gòu)建方面的強化,例如:
支持枚舉的構(gòu)建和編譯
在 Vito 的建議下增加了多維數(shù)組反解器
在 Vito 的建議下增加了鋸齒數(shù)組反解器
命名反解器支持鋸齒和多維數(shù)組
二、我們經(jīng)歷了哪些實踐
- 深度克隆:https://github.com/night-moon-studio/DeepClone
本項目由 Net_win、Vito、myFirstway、白開水組隊開發(fā),可在運行時動態(tài)生成克隆方法。深度克隆作為基礎(chǔ)項目,鍛煉了開源工作者的類型辨識技能,趟過了坑為以后的封裝之路打下基礎(chǔ)。
- 快速調(diào)用:https://github.com/night-moon-studio/NCaller
本項目由 AzulX 和 FUTURE* 開發(fā),可以對運行時實體類、靜態(tài)類的字段/屬性進(jìn)行動態(tài)調(diào)用和賦值,目前有兩個主要分支,哈希二叉查找算法動態(tài)實現(xiàn)以及 FUTURE* 的指針二叉查找算法動態(tài)實現(xiàn),在算法的動態(tài)實現(xiàn)上,Natasha 表現(xiàn)出了相當(dāng)強大的優(yōu)勢。
三、談一談‘熱更新’
'熱更新'是 Core3.0 的亮點特性之一,不少小伙伴在看到譯文的時候可能就已經(jīng)想到了N多場景,歷經(jīng)兩代 .NET 的洗禮,‘熱更新’現(xiàn)在發(fā)展到什么樣子了?下面簡單談一談:
.NET Framework 開荒時期有 AppDomain 域之隔離術(shù),包括有創(chuàng)建、加載程序集、卸載等方法,囊括百家程序集,一刀以斬之。對于前輩們來說談到 AppDomain 可以口若懸河滔滔不絕,可惜我進(jìn)入 C# 時間比較晚,對 AppDomain 的印象并不是很深,在應(yīng)用上也沒有什么造詣,僅此泛泛而言。
時間進(jìn)入了 .NETCore 時代,AppDomain 在升級大潮中受到了致命打擊, Create 方法和 Unload 方法經(jīng)歲月升級后的源碼中充斥著 throw 和 throw ,完全喪失了功能,取而代之的是 ALC(AssemblyLoadContext) ,Core3.0 的 ALC 是一個更為完善的操作類,官方為其定義了三大洪荒場景:
1、插件編程2、動態(tài)編譯,運行/刷新代碼,網(wǎng)站/腳本引擎3、外部程序集的一次性內(nèi)省(我個人理解就是類的信息,IsArray , IsClass 這種元數(shù)據(jù)只讀屬性)據(jù)描述:Roslyn 之前一直用 AppDomain , 每個測試都腰酸背痛相當(dāng)慢,自從換了 ALC( A blue Ca.) 一口氣上5樓不費勁!官方畫了大餅:未來 Roslyn 分析器執(zhí)行編譯時也都在ALC里進(jìn)行,用完就卸載,卸磨就殺驢。
AppDomain 當(dāng)初被定位在高性能、安全,歷史證明這個定位跟 GPS 一樣不準(zhǔn),ASP.NET 深受其害,歷史車輪碾過了 ASP.NET 迎來了 ASP.NET Core ,在域功能被閹割的期間,ASP.NET Core 轉(zhuǎn)向了相對靜態(tài)的模型,增加了若干學(xué)習(xí)成本,詳見 dotnet watch 命令。還有 Razor , 它從 .cshtml 編譯到 .dll 的環(huán)境就是 ALC ,自建了一個名為 Razor-Server 的域環(huán)境。
另外還涉及到 LINQPad 和 Prism 框架, 精力有限,誰有興趣就去研究研究吧。
ALC 的場景和案例可能激起了您的好奇心,下面講一下 ALC 的應(yīng)用:
我們可以在程序里創(chuàng)建多個 ALC 實例,但前提是你需要繼承并實現(xiàn)它。每一個 ALC 的實例都是一個域(這里我就不叫它上下文了)。程序剛跑起來的時候是在 Defualt 域中的,這個域?qū)儆谙到y(tǒng)域卸不了,又稱為共享域,不同域之間是無法訪問和引用的不同域中信息的,卻共用 Default 域中的信息,這個域至關(guān)重要,所以盡量避免向其中加載亂七八糟的程序集。
ALC 的使用需要注意以下幾點:
1、子類繼承時需指定 ALC 的構(gòu)造參數(shù),base(isCollectible) , 這個參數(shù)可以賦予 ALC 卸載的能力。2、時刻注意反射信息的引用,只有清除引用,才能保證 ALC 實例被 GC 回收。3、在針對不同域的編程時可使用 EnterContextualReflection 方法鎖住域內(nèi)上下文,EnterContextualReflection 方法是放在 using 里的,這樣你的花括號內(nèi)就是一個域,并用 CurrentContextualReflectionContext 屬性來獲取當(dāng)前操作域。4、注意 ALC 被線程占用的情況,被占用的對象是無法被回收的,如果你在測試中沒有達(dá)到預(yù)期,除了排除代碼問題之外你還需要注意函數(shù)是否被內(nèi)聯(lián)進(jìn)入主線程或一個帶有阻塞功能的線程,如果你不確定,可以在方法上使用 [MethodImpl(MethodImplOptions.NoInlining)] 阻止代碼內(nèi)聯(lián)優(yōu)化,正常情況下優(yōu)化功能是開啟的 。5、插件加載要注意與插件 dll 同目錄的依賴文件,3.0 提供了 AssemblyDependencyResolver 操作類自動解析依賴,建議使用帶有.deps.json文件的完整插件。6、當(dāng)你的外部文件引用并使用了 Json.net/SqlConnection 等(測試日期9月3日),會造成不可回收的情況,不是你的代碼出問題了,而是庫本身的問題(待解決,3.1或者5.0)。對 ALC 封裝的一些建議:
1、如果沒有非托管代碼,盡量不要在析構(gòu)函數(shù)里折騰代碼。2、如果你的域管理代碼有些復(fù)雜,建議對外給個 IDispose 接口,以便清除對該域的程序集、元數(shù)據(jù)等信息的引用。3、肉眼觀測內(nèi)存時,測試代碼中盡量不要在 Main 函數(shù)里做元數(shù)據(jù)的相關(guān)操作,主線程是 GC 的一個干擾點。4、若對內(nèi)存的開銷比較敏感,請盡可能分域,并結(jié)合弱引用實現(xiàn)創(chuàng)建與銷毀。5、有時顯式調(diào)用 Unload 方法會報異常,可以在 Dispose 里清除完引用之后再使用,實測你不用 Unload 方法也能回收。Core3.0 中隨 ALC 一起的還有反射的自省信息。
例如:MemberInfo.IsCollectible 、 Assembly.IsCollectible 等元數(shù)據(jù),它將告訴你它是否能被回收,當(dāng)然了這種自省的信息都是只讀的。說到只讀,.NET 中還存有一條進(jìn)化路線即 :ReflectionOnlyLoad -> TypeLoader -> MetadataLoadContext (感謝WeiHanLi提供的信息), 只讀元數(shù)據(jù),相比 ALC 可執(zhí)行,可調(diào)用,MLC ( MetadataLoadContext 在包 System.Reflection.MetadataLoadContext 中) 關(guān)注的是元數(shù)據(jù)只讀操作,它并不能執(zhí)行程序集的內(nèi)容,僅僅反射出元數(shù)據(jù),配套使用的是PathAssemblyResolver.
對于無法卸載的情況,官方建議使用 windbg sos 組件進(jìn)行調(diào)試,新版 sos 將獨立出來,各位可以使用以下命令進(jìn)行安裝(建議開源工作者在封裝此功能時添加UT測試檢測卸載功能,盡可能保證在正常的情況下不需要用戶自己去調(diào)試)。
$ dotnet tool install -g dotnet-sos --version 3.0.0-preview8.19412.1
$ dotnet-sos install
更多的實踐還需要大家去探索。
四、Natasha是如何實現(xiàn)‘熱更新’的
- 關(guān)于域的操作您可以
- 關(guān)于程序域的插件操作
- 關(guān)于程序集的操作
- 結(jié)合域和程序集動態(tài)編譯,實例
文章內(nèi)容未經(jīng)許可,禁止轉(zhuǎn)載!
Natasha 屬于 NCC(.NET Core Community) 成員項目。
項目倉庫:https://github.com/dotnetcore/Natasha
轉(zhuǎn)載于:https://www.cnblogs.com/NMSLanX/p/11456944.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的兼容 .NET Core3.0, Natasha 框架实现 隔离域与热编译操作的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 心情-天气
- 下一篇: 遇到问题了 .net项目发布到iis6,