日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【A】兼容Core3.0后 Natasha 的隔离域与热编译操作。

發布時間:2023/12/4 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【A】兼容Core3.0后 Natasha 的隔离域与热编译操作。 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章轉載授權級別:A ????????預計閱讀時間:15分鐘

一、? 2.0預覽版本增加了哪些功能

大部分為底層的升級優化,例如:

  • 引擎兼容 Core3.0

  • 優化編譯流程,增加編譯前語法檢測及日志,統一采用流加載方式

  • 在 Vito 的建議下改進了日志目錄及命名

  • ALC 同類覆蓋編譯

  • 支持域的創建、卸載、鎖操作

  • 支持共享域與獨立域協作

  • 支持獨立域的程序集創建、覆蓋操作

  • 支持插件及依賴的加載

構建方面的強化,例如:

  • 支持枚舉的構建和編譯

  • 在 Vito 的建議下增加了多維數組反解器

  • 在 Vito 的建議下增加了鋸齒數組反解器

  • 命名反解器支持鋸齒和多維數組

二、我們經歷了哪些實踐

深度克隆:https://github.com/night-moon-studio/DeepClone

本項目由 Net_win、Vito、myFirstway、白開水組隊開發,可在運行時動態生成克隆方法。深度克隆作為基礎項目,鍛煉了開源工作者的類型辨識技能,趟過了坑為以后的封裝之路打下基礎。

快速調用:https://github.com/night-moon-studio/NCaller

本項目由 AzulX 和 FUTURE* 開發,可以對運行時實體類、靜態類的字段/屬性進行動態調用和賦值,目前有兩個主要分支,哈希二叉查找算法動態實現以及 FUTURE* 的指針二叉查找算法動態實現,在算法的動態實現上,Natasha 表現出了相當強大的優勢。

三、談一談‘熱更新’

'熱更新'是 Core3.0 的亮點特性之一,不少小伙伴在看到譯文的時候可能就已經想到了N多場景,歷經兩代 .NET 的洗禮,‘熱更新’現在發展到什么樣子了?下面簡單談一談:

.NET Framework 開荒時期有 AppDomain 域之隔離術,包括有創建、加載程序集、卸載等方法,囊括百家程序集,一刀以斬之。對于前輩們來說談到 AppDomain 可以口若懸河滔滔不絕,可惜我進入 C# 時間比較晚,對 AppDomain 的印象并不是很深,在應用上也沒有什么造詣,僅此泛泛而言。

時間進入了 .NETCore 時代,AppDomain 在升級大潮中受到了致命打擊, Create 方法和 Unload 方法經歲月升級后的源碼中充斥著 throw 和 throw ,完全喪失了功能,取而代之的是?ALC(AssemblyLoadContext) ,Core3.0 的 ALC 是一個更為完善的操作類,官方為其定義了三大洪荒場景:

????1、插件編程

????2、動態編譯,運行/刷新代碼,網站/腳本引擎

????3、外部程序集的一次性內省(我個人理解就是類的信息,IsArray ,? IsClass 這種元數據只讀屬性)

據描述:Roslyn 之前一直用 AppDomain , 每個測試都腰酸背痛相當慢,自從換了 ALC( A blue Ca.) 一口氣上5樓不費勁!官方畫了大餅:未來 Roslyn 分析器執行編譯時也都在ALC里進行,用完就卸載,卸磨就殺驢。

AppDomain 當初被定位在高性能、安全,歷史證明這個定位跟 GPS 一樣不準,ASP.NET 深受其害,歷史車輪碾過了 ASP.NET 迎來了 ASP.NET Core ,在域功能被閹割的期間,ASP.NET Core?轉向了相對靜態的模型,增加了若干學習成本,詳見?dotnet watch?命令。還有 Razor , 它從 .cshtml 編譯到 .dll 的環境就是 ALC ,自建了一個名為 Razor-Server 的域環境。

另外還涉及到 LINQPad 和 Prism 框架, 精力有限,誰有興趣就去研究研究吧。

ALC 的場景和案例可能激起了您的好奇心,下面講一下 ALC 的應用:

我們可以在程序里創建多個 ALC 實例,但前提是你需要繼承并實現它。每一個 ALC 的實例都是一個域(這里我就不叫它上下文了)。程序剛跑起來的時候是在 Defualt 域中的,這個域屬于系統域卸不了,又稱為共享域,不同域之間是無法訪問和引用的不同域中信息的,卻共用 Default 域中的信息,這個域至關重要,所以盡量避免向其中加載亂七八糟的程序集。

ALC 的使用需要注意以下幾點:

??? 1、子類繼承時需指定 ALC 的構造參數,base(isCollectible) , 這個參數可以賦予 ALC 卸載的能力。

??? 2、時刻注意反射信息的引用,只有清除引用,才能保證 ALC 實例被 GC 回收。

????3、在針對不同域的編程時可使用 EnterContextualReflection 方法鎖住域內上下文,EnterContextualReflection?方法是放在 using 里的,這樣你的花括號內就是一個域,并用 CurrentContextualReflectionContext 屬性來獲取當前操作域。

??? 4、注意 ALC 被線程占用的情況,被占用的對象是無法被回收的,如果你在測試中沒有達到預期,除了排除代碼問題之外你還需要注意函數是否被內聯進入主線程或一個帶有阻塞功能的線程,如果你不確定,可以在方法上使用 [MethodImpl(MethodImplOptions.NoInlining)] 阻止代碼內聯優化,正常情況下優化功能是開啟的?。

??? 5、插件加載要注意與插件 dll 同目錄的依賴文件,3.0 提供了 AssemblyDependencyResolver 操作類自動解析依賴,建議使用帶有.deps.json文件的完整插件。

??? 6、當你的外部文件引用并使用了 Json.net/SqlConnection 等(測試日期9月3日),會造成不可回收的情況,不是你的代碼出問題了,而是庫本身的問題(待解決,3.1或者5.0)。

????

對 ALC 封裝的一些建議:

??? 1、如果沒有非托管代碼,盡量不要在析構函數里折騰代碼。

??? 2、如果你的域管理代碼有些復雜,建議對外給個 IDispose 接口,以便清除對該域的程序集、元數據等信息的引用。

??? 3、肉眼觀測內存時,測試代碼中盡量不要在 Main 函數里做元數據的相關操作,主線程是 GC 的一個干擾點。

??? 4、若對內存的開銷比較敏感,請盡可能分域,并結合弱引用實現創建與銷毀。

??? 5、有時顯式調用 Unload 方法會報異常,可以在 Dispose 里清除完引用之后再使用,實測你不用 Unload 方法也能回收。

Core3.0 中隨 ALC 一起的還有反射的自省信息。

例如:MemberInfo.IsCollectible?、?Assembly.IsCollectible?等元數據,它將告訴你它是否能被回收,當然了這種自省的信息都是只讀的。說到只讀,.NET 中還存有一條進化路線即?:ReflectionOnlyLoad -> TypeLoader -> MetadataLoadContext (感謝WeiHanLi提供的信息), 只讀元數據,相比 ALC 可執行,可調用,MLC (?MetadataLoadContext 在包?System.Reflection.MetadataLoadContext 中) 關注的是元數據只讀操作,它并不能執行程序集的內容,僅僅反射出元數據,配套使用的是PathAssemblyResolver.?

對于無法卸載的情況,官方建議使用 windbg sos 組件進行調試,新版 sos 將獨立出來,各位可以使用以下命令進行安裝(建議開源工作者在封裝此功能時添加UT測試檢測卸載功能,盡可能保證在正常的情況下不需要用戶自己去調試)。

$ dotnet tool install -g dotnet-sos --version 3.0.0-preview8.19412.1$ dotnet-sos install

更多的實踐還需要大家去探索。

四、Natasha是如何實現‘熱更新’的

據以上信息,Natasha2.0 中動態構建遵循以下結構。

這兩幅圖說展示了 Natasha 中自定義編譯域的結構,如果在創建程序集時不指定名字,程序集名將以 GUID 形式創建,故名隨機程序集。在編譯時未被移除的引用都將參與編譯,該引用的來源:1、共享域;2、當前域;

  • 關于域的操作您可以

//創建一個域 DomainManagment.Create("MyDomain"); //移除一個域,移除將無法進行DomainManagment的其他任何操作 DomainManagment.Remove("MyDomain"); //判斷域是否被卸載(被GC回收) DomainManagment.IsDeleted("MyDomain"); //獲取一個ALC上下文 DomainManagment.Get("MyDomain"); //鎖住已存在的域上下文 using(DomainManagment.Lock("MyDomain")) { var domain = DomainManagment.CurrentDomain; //code?in?'MyDomain'?domain? } //創建并鎖定一個域上下文 using(DomainManagment.CreateAndLock("MyDomain")) { var domain = DomainManagment.CurrentDomain; //code in 'MyDomain' domain }

  • 關于程序域的插件操作

//向域中注入插件? string dllPath = @"1/2/3.dll"; var domain = DomainManagment.Get/Create("MyDomain"); var assembly = domain.LoadFile(dllPath); //鎖域與插件解構操作 string dllPath = @"1/2/3.dll"; using(DomainManagment.CreateAndLock("MyDomain")) { var (Assembly,TypeCache) = dllPath; //Assembly:?Assembly //TypeCache:?ConcurrentDictionary<string,Type>? } //將引用從當前域內移除,下次編譯將不會帶著該程序集的信息 //下面方法三選一均可實現引用移除操作 domain.RemoveDll(dllPath); domain.RemoveAssembly(assembly); domain.RemoveType(type);

  • 關于程序集的操作:

//從指定域創建一個程序集操作實例 var?asm?=?domain.CreateAssembly("MyAssembly"); //向程序集中添加一段已經寫好的類/結構體/接口/枚舉 asm.AddScript(@"using?xxx;?namespace?xxx{xxxx}"); asm.AddFile(@"Class1.cs"); //使用Natasha內置的操作類 asm.CreateEnum(name=null); asm.CreateClass(name=null); asm.CreateStruct(name=null); asm.CreateInterface(name=null); //使用Natasha內置的方法操作類 //并不是很推薦使用這兩個方法 //建議在一個單獨的程序集內編譯方法? asm.CreateFastMethod(name=null); asm.CreateFakeMethod(name=null); //使用程序集進行編譯并獲得程序集 var?assembly?=?asm.Complier(); asm.GetType(name);

  • 結合域和程序集動態編譯,實例

using(DomainManagment.CreateAndLock("MyDomain")) { var domain = DomainManagment.CurrentDomain; var assembly = domain.CreateAssembly("MyAssembly"); //創建一個接口 assembly .CreateInterface("InterfaceTest") .Using("System") .OopAccess(AccessTypes.Public) .OopBody("string ShowMethod(string str);"); //創建一個類并實現接口 assembly .CreateClass("TestClass") .Using("System") .OopAccess(AccessTypes.Public)???????? .Inheritance("InterfaceTest") .Method(method => method .MemberAccess(AccessTypes.Public) .Name("ShowMethod") .Param<string>("str") .Body("return?str+\" World!\";") .Return<string>()); //編譯并獲取類型 var result = assembly.Complier(); var type = assembly.GetType("TestClass"); //Operator默認單獨創建一個程序集 var @delegate = FastMethodOperator.New .Using(type) .MethodBody(@" TestClass obj = new TestClass(); return?obj.ShowMethod(arg);") .Complie<Func<string,?string>>(); @delegate("Hello");??//result?=?"Hello?World!"; domain.Dispose(); //卸磨殺驢 }

不要從公眾號里復制代碼到VS,會有意外字符。

五、Bug有緣人

訪問以下鏈接:https://github.com/dotnet/corefx/blob/1b3a095c277476b746e6fb9884662cf12334c6a1/src/System.Reflection.MetadataLoadContext/src/System/Reflection/MetadataLoadContext.Loading.cs

自右向左選中 MetadataLoadContext , 如果頁面崩潰了,?老鐵握爪。

https://github.com/dotnetcore

打賞一杯酒,削減三分愁。跟著我們走,脫發包你有。

組織打賞賬戶為檸檬的賬戶,請標注「NCC」,并留下您的名字,以下地址可查看收支明細:https://github.com/dotnetcore/Home/blob/master/Statement-of-Income-and-Expense.md

OpenNCC,專注.NET技術的公眾號

https://www.dotnetcore.xyz

微信ID:OpenNCC

長按左側二維碼關注

歡迎打賞組織

給予我們更多的支持

總結

以上是生活随笔為你收集整理的【A】兼容Core3.0后 Natasha 的隔离域与热编译操作。的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。