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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

通过 .NET NativeAOT 实现用户体验升级

發(fā)布時間:2023/12/4 asp.net 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 通过 .NET NativeAOT 实现用户体验升级 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

前言

TypedocConverter 是我先前因幫助維護(hù) monaco-editor-uwp 但苦于 monaco editor 的 API 實(shí)在太多,手寫 C# 的類型綁定十分不劃算而發(fā)起的一個項(xiàng)目。

這個工具可以將 typedoc 根據(jù) TypeScript 生成的 JSON 文件直接生成對應(yīng)的 C# 類型綁定代碼,并提供完整的 JSON 序列化支持,因此使用這個工具可以大大降低移植 TypeScript 庫到 .NET 上的困難。(至于為什么是從 typedoc 而不是從 TypeScript 直接 parse,其實(shí)只是因?yàn)樘珣辛瞬幌雽?TypeScript 的 parser)

TypedocConverter 使用 F# 編寫,雖然使用 .NET 5 可以做到程序集裁剪后使用單文件自托管發(fā)布,但是我一直在想如果能使用 AOT 技術(shù)將整個程序編譯為 native binary 那就好了,這樣的話用戶在使用的時候?qū)⒉恍枰\(yùn)行 .NET 的運(yùn)行時,也不需要 JIT,而是直接運(yùn)行機(jī)器代碼。

工具除了功能性之外,最重要的就是用戶體驗(yàn),這樣做將大大提升程序的啟動速度(雖然原本已經(jīng)夠快了,但是我想將 100ms 的啟動時間縮短到不到 1ms),使得用戶使用該工具時不需要任何的等待。

AOT 方案調(diào)研

.NET 一直以來都有一個叫做 CoreRT 的項(xiàng)目,使用該工具可以將 .NET 程序集編譯到 native binary,然而這個項(xiàng)目自從 2018 年官方就沒有再積極維護(hù)。但是由于社區(qū)的強(qiáng)烈呼聲以及某個微軟的合作伙伴的項(xiàng)目需要 AOT 技術(shù),并表示如果沒有這項(xiàng)技術(shù)將不再使用 .NET,于是這個項(xiàng)目原地復(fù)活,以 NativeAOT 的名字轉(zhuǎn)移到了 runtimelab 并作為 .NET 6 的 P0(最高) 優(yōu)先級實(shí)驗(yàn)性工作項(xiàng)(即提供帶支持的官方 preview,而不再是原來的萬年 alpha),目前支持 win-x64、linux-x64 和 osx-x64,對于 ARM64 、移動平臺和瀏覽器(WebAssembly)的支持在計(jì)劃當(dāng)中。

借著這個契機(jī),我決定使用該方案將項(xiàng)目編譯為原生鏡像。

NativeAOT 原理

.NET 的 NativeAOT 的思路其實(shí)很簡單:

  • 首先需要一個 AOT 友好的、用于 NativeAOT 的核心庫 (System.Private.CoreLib)實(shí)現(xiàn),提供類型和實(shí)現(xiàn)查找、類型解析等方法

  • 掃描程序集,記錄用到的類型和方法

  • 調(diào)用 RyuJIT 接口,生成類型的元數(shù)據(jù),為所有的方法生成代碼,最終產(chǎn)生出 obj 二進(jìn)制文件

  • 調(diào)用鏈接器(MSVC 或 clang),將產(chǎn)生的 obj 與 GC 和系統(tǒng)庫等鏈接成為最終的可執(zhí)行文件

現(xiàn)階段 NativeAOT 基本已經(jīng)完成,剩余的部分工作則是一些修補(bǔ)和完善,以及對新版本 .NET 的跟進(jìn)(目前還沒有跟進(jìn) C# 8 之后牽扯到運(yùn)行時修改的特性,如默認(rèn)接口方法實(shí)現(xiàn)和模塊初始化器等等)。

可能你會問這和 .NET Native 技術(shù)有何不同?不同之處在于 .NET Native 使用 UTC 編譯器(MSVC 后端)進(jìn)行代碼生成,而 NativeAOT 使用 RyuJIT 進(jìn)行代碼生成。

關(guān)于 .NET NativeAOT 完整的使用文檔可以參考:using-native-aot。

針對 NativeAOT 改造項(xiàng)目

NativeAOT 使用非常簡單,只需要修改 csproj 項(xiàng)目文件即可:

<PropertyGroup><IlcOptimizationPreference>Speed</IlcOptimizationPreference><IlcFoldIdenticalMethodBodies>true</IlcFoldIdenticalMethodBodies> </PropertyGroup> <ItemGroup><PackageReference Include="Microsoft.DotNet.ILCompiler" Version="6.0.0-*" /> </ItemGroup>

IlcOptimizationPreference?指定?Speed?表示以最大性能為目標(biāo)生成代碼(如果指定?Size?則表示以最小程序?yàn)槟繕?biāo)生成代碼)。

IlcFoldIdenticalMethodBodies?參數(shù)則可以將相同的方法體合并,有助于減小體積。

最后則是新的?Microsoft.DotNet.ILCompiler,這是 NativeAOT 編譯器本體,通過 wildcard 指定?6.0.0-*?版本,這樣每次編譯都會獲取最新的版本。

由于?Microsoft.DotNet.ILCompiler?來自實(shí)驗(yàn)倉庫的 artifacts,而沒有發(fā)布在官方的 nuget 源,需要新建 nuget.config 額外將實(shí)驗(yàn)倉庫的 artifacts 作為源引入:

<?xml version="1.0" encoding="utf-8"?> <configuration><packageSources><add key="dotnet-experimental" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-experimental/nuget/v3/index.json" /></packageSources> </configuration>

如此一來便大功告成了,這就開始編譯:

dotnet publish -c Release -r win-x64

伴隨而來的是大量的警告:

AOT analysis warning IL9700: Microsoft.FSharp.Reflection.FSharpType.MakeFunctionType(Type,Type): Calling 'System.Type.MakeGenericType(Type[])' which has `RequiresDynamicCodeAttribute` can break functionality when compiled fully ahead of time. The native code for this instantiation might not be available at runtime. AOT analysis warning IL9700: Microsoft.FSharp.Reflection.FSharpValue.MakeFunction(Type,FSharpFunc`2<Object,Object>): Calling 'System.Type.MakeGenericType(Type[])' which has `RequiresDynamicCodeAttribute` can break functionality when compiled fully ahead of time. The native code for this instantiation might not be available at runtime. ...

觀察警告可以發(fā)現(xiàn),這是分析器報(bào)出來的,理由很簡單:NativeAOT 是不支持運(yùn)行時動態(tài)代碼生成的,但是?MakeGenericType?在需要在運(yùn)行時產(chǎn)生類型,因此可能不受支持。

為什么說是可能呢?因?yàn)?NativeAOT 條件下,不支持運(yùn)行時產(chǎn)生新的類型,但是對于已經(jīng)生成代碼的類型則是完全支持的。

由于項(xiàng)目沒有用到?System.Reflection.Emit?在運(yùn)行時動態(tài)織入 IL,也沒有用到?Assembly.LoadFile?等動態(tài)加載程序集,更沒有用到 C++/CLI 和 COM,因此是 NativeAOT 兼容的。

編譯速度尚可,只等待了半分鐘。編譯完成后產(chǎn)生了一個 29mb 的 exe,體積還不夠優(yōu)秀,但是先運(yùn)行看看:

> ./TypedocConverter [Error] No input file Typedoc Converter Arguments: --inputfile [file]: input file --namespace [namespace]: specify namespace for generated code --splitfiles [true|false]: whether to split code to different files --outputdir [path]: used for place code files when splitfiles is true --outputfile [path]: used for place code file when splitfiles is false --number-type [int/decimal/double...]: config for number type mapping --promise-type [CLR/WinRT]: config for promise type mapping, CLR for Task and WinRT for IAsyncAction/IAsyncOperation --any-type [object/dynamic...]: config for any type mapping --array-type [Array/IEnumerable/List...]: config for array type mapping --nrt-disabled [true|false]: whether to disable Nullable Reference Types --use-system-json [true|false]: whether to use System.Text.Json instead of Newtonsoft.Json

一瞬間就運(yùn)行了起來,完全感受不到啟動時間(體感小于 1ms),這個體驗(yàn)太爽了。

可是正當(dāng)我高興的時候,使用一個實(shí)際的 JSON 文件對功能進(jìn)行測試,卻報(bào)錯了:

Unhandled Exception: EETypeRva:0x013EC198(System.Reflection.MissingRuntimeArtifactException): MakeGenericMethod() cannot create this generic method instantiation because no code was generated for it: 'Microsoft.FSharp.Collections.ListModule.OfSeq<System.Int32>(System.Collections.Generic.IEnumerable<System.Int32>)'.at Internal.Reflection.Core.Execution.ExecutionEnvironment.GetMethodInvoker(RuntimeTypeInfo, QMethodDefinition, RuntimeTypeInfo[], MemberInfo) + 0x144at System.Reflection.Runtime.MethodInfos.NativeFormat.NativeFormatMethodCommon.GetUncachedMethodInvoker(RuntimeTypeInfo[], MemberInfo) + 0x50at System.Reflection.Runtime.MethodInfos.RuntimeMethodInfo.get_MethodInvoker() + 0xa1at System.Reflection.Runtime.MethodInfos.RuntimeNamedMethodInfo`1.MakeGenericMethod(Type[]) + 0x104...

可以看到方法?Microsoft.FSharp.Collections.ListModule.OfSeq<System.Int32>(System.Collections.Generic.IEnumerable<System.Int32>?缺失了。

這是因?yàn)?NativeAOT 編譯器并沒有通過代碼路徑分析出該類型,因此沒有為該類型生成代碼,導(dǎo)致運(yùn)行時嘗試創(chuàng)建該類型時由于找不到實(shí)現(xiàn)代碼而出錯。

因此,需要通過 Runtime Directives 指示編譯器生成指定類型和方法的代碼,方法是創(chuàng)建一個?rd.xml?并引入項(xiàng)目:

<ItemGroup><RdXmlFile Include="rd.xml" /></ItemGroup>

然后在?rd.xml?中編寫需要編譯器額外生成的類型和方法。經(jīng)過一番試錯之后,我寫出了如下的代碼:

<Directives><Application><Assembly Name="FSharp.Core" Dynamic="Required All"><Type Name="Microsoft.FSharp.Collections.ListModule" Dynamic="Required All"><Method Name="OfSeq" Dynamic="Required"><GenericArgument Name="System.Int32,System.Private.CoreLib" /></Method></Type><Type Name="Microsoft.FSharp.Core.PrintfImpl+Specializations`3[[System.Object,System.Private.CoreLib],[System.Object,System.Private.CoreLib],[System.Object,System.Private.CoreLib]]" Dynamic="Required All"><Method Name="CaptureFinal1" Dynamic="Required"><GenericArgument Name="System.Object,System.Private.CoreLib" /></Method><Method Name="CaptureFinal2" Dynamic="Required"><GenericArgument Name="System.Object,System.Private.CoreLib" /><GenericArgument Name="System.Object,System.Private.CoreLib" /></Method><Method Name="CaptureFinal3" Dynamic="Required"><GenericArgument Name="System.Object,System.Private.CoreLib" /><GenericArgument Name="System.Object,System.Private.CoreLib" /><GenericArgument Name="System.Object,System.Private.CoreLib" /></Method><Method Name="OneStepWithArg" Dynamic="Required"><GenericArgument Name="System.Object,System.Private.CoreLib" /></Method><Method Name="Capture1" Dynamic="Required"><GenericArgument Name="System.Object,System.Private.CoreLib" /><GenericArgument Name="System.Object,System.Private.CoreLib" /></Method><Method Name="Capture2" Dynamic="Required"><GenericArgument Name="System.Object,System.Private.CoreLib" /><GenericArgument Name="System.Object,System.Private.CoreLib" /><GenericArgument Name="System.Object,System.Private.CoreLib" /></Method><Method Name="Capture3" Dynamic="Required"><GenericArgument Name="System.Object,System.Private.CoreLib" /><GenericArgument Name="System.Object,System.Private.CoreLib" /><GenericArgument Name="System.Object,System.Private.CoreLib" /><GenericArgument Name="System.Object,System.Private.CoreLib" /></Method></Type> </Assembly><Assembly Name="System.Linq" Dynamic="Required All"><Type Name="System.Linq.Enumerable" Dynamic="Required All"><Method Name="ToArray" Dynamic="Required"><GenericArgument Name="System.Int32,System.Private.CoreLib" /></Method></Type></Assembly></Application> </Directives>

稍微對上面的東西進(jìn)行一下解釋:Name 用于指定類型,,?前后分別是類型的完整名稱和類型來自的程序集名稱,.NET 中的各種基礎(chǔ)類型都來源于?System.Private.CoreLib?或?mscorlib。詳細(xì)的格式說明可以參考 rd-xml-format。

在 .NET 中,編譯器會為所有的值類型的泛型參數(shù)特化一份實(shí)現(xiàn),而所有的引用類型參數(shù)共享一份實(shí)現(xiàn)。這么做其實(shí)原因顯而易見,因?yàn)橐妙愋捅澈笾皇且粋€指針罷了。因此根據(jù)這個特點(diǎn),所有的引用類型都無需指定實(shí)際的類型參數(shù),統(tǒng)一指定一個?System.Object?就好了;而對于值類型作為類型參數(shù)則需要指出生成什么類型的代碼。

經(jīng)過上面一番折騰之后,重新編譯運(yùn)行,這次所有的功能均正常了,啟動速度飛快,運(yùn)行時性能也非常棒,并且純靜態(tài)鏈接無需安裝任何運(yùn)行時就能運(yùn)行,體驗(yàn)幾乎和 C++ 編寫出來的程序一樣。

程序體積優(yōu)化

上面一系列操作之后,雖然啟動和運(yùn)行速度很快,但是生成的程序大小有 30 mb,還是有些大,那么接下來在不犧牲運(yùn)行時代碼性能的情況下,針對程序體積進(jìn)行優(yōu)化。

首先指定?TrimMode為?Link,這可以使 NativeAOT 采用更加激進(jìn)的程序集剪裁方案,將代碼路徑中沒有被引用的代碼以方法為粒度刪掉;另外,想到自己的程序不需要國際化支持,因此可以刪除掉沒有用的多語言支持及其資源文件。

<PropertyGroup><TrimMode>Link</TrimMode><InvariantGlobalization>true</InvariantGlobalization> </PropertyGroup>

重新進(jìn)行編譯,這個時候產(chǎn)生的 exe 大小只有 27mb 了,運(yùn)行測試:

Unhandled Exception: Newtonsoft.Json.JsonSerializationException: Unable to find a constructor to use for type Definitions+Reflection. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute. Path 'id', line 2, position 6.at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateNewObject(JsonReader, JsonObjectContract, JsonProperty, JsonProperty, String, Boolean&) + 0x1d1at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader, Type, JsonContract, JsonProperty, JsonContainerContract, JsonProperty, Object) + 0x2ccat Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader, Type, JsonContract, JsonProperty, JsonContainerContract, JsonProperty, Object) + 0xa4at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader, Type, Boolean) + 0x26eat Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader, Type) + 0xf8at Newtonsoft.Json.JsonConvert.DeserializeObject(String, Type, JsonSerializerSettings) + 0x93at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String, JsonSerializerSettings) + 0x2bat Program.main$cont@84(JsonSerializerSettings, Definitions.Config, Unit) + 0x31at TypedocConverter!<BaseAddress>+0x83a0ca

根據(jù)報(bào)錯信息我們知道是 JSON 反序列化過程出了問題,問題在于?Definitions+Reflection?類型被裁剪掉了。由于我知道我自己的程序內(nèi)進(jìn)行 JSON 反序列化的目標(biāo)類型都是來自于我自己的程序集本身,因此不必使用?rd.xml?那么麻煩,只需要告訴編譯器不要裁剪我自己的程序集中的類型即可(這對于泛型類實(shí)例無效,因?yàn)榉盒皖愋蛯?shí)現(xiàn)是需要特化的):

<ItemGroup><TrimmerRootAssembly Include="TypedocConverter" /> </ItemGroup>

接下來重新編譯運(yùn)行,這次沒問題了。

最終程序的大小是 27mb,相比 30mb 并沒有小太多,不過這也正常,畢竟前面寫的?rd.xml?中,由于偷懶,通過?Dynamic="Require All"?保留了 F# 核心庫中的所有類型。如果我去掉?Dynamic="Require All"?的話,最終編譯出 22mb 的二進(jìn)制文件,但是需要更多的精力調(diào)研有哪些類型需要寫進(jìn)?rd.xml。

通過 zip 壓縮之后只剩下 11mb,這個體積我覺得已經(jīng)不錯了。

當(dāng)然,要注意的是,Windows 下調(diào)試符號文件默認(rèn)作為單獨(dú)的 pdb 文件提供,而在 *inx 下調(diào)試符號是直接內(nèi)嵌到程序二進(jìn)制數(shù)據(jù)中的,因此在非 Windows 平臺下需要使用?strip?命令將符號裁剪掉,否則你將得到一個非常大的二進(jìn)制程序文件。

strip ./TypedocConverter

想要看看最終效果的可以去此處下載含 Native 名稱的 Release 文件體驗(yàn):github.com/hez2010/Type。

到這里有人可能好奇 NativeAOT 最小能做到多小?經(jīng)過實(shí)驗(yàn),禁用反射并取消 root 所有程序集后的 hello world 項(xiàng)目可以做到不到 1mb 的體積。

已知問題和限制

.NET NativeAOT 預(yù)計(jì)會在 .NET 6 將會為嘗鮮者提供帶支持的預(yù)覽(其實(shí)已經(jīng)足夠穩(wěn)定),現(xiàn)階段有一些比較影響使用的已知問題,我將在這里列出。

由于缺少實(shí)現(xiàn)而不支持(主要是 C# 8 之后的需要運(yùn)行時改變的特性),但是短期內(nèi)會被解決的問題:

  • 不支持含泛型方法的默認(rèn)接口方法實(shí)現(xiàn)

  • 不支持協(xié)變返回

  • try-catch 語句中不支持?catch (T),即將泛型參數(shù)作為?catch?的異常類型

  • 不支持模塊初始化器

短期內(nèi)不會被解決的問題:

  • 不支持 COM

  • 不支持 C++/CLI

受限于運(yùn)行時無 JIT 而無法實(shí)現(xiàn)的:

  • 運(yùn)行時動態(tài)生成代碼(如:System.Reflection.Emit)

  • 運(yùn)行時動態(tài)加載程序集(如:Assembly.LoadFile)

  • 無限泛型遞歸調(diào)用

有人可能不理解什么叫做無限泛型遞歸調(diào)用,我通過代碼解釋一下,假如你編寫了如下代碼:

public void Foo<T>() {if (bar){Foo<U<T>>();} }

那么會導(dǎo)致編譯器 Stack Overflow。原因是因?yàn)榇a中將?U<T>>?類型代入了?T,如果是不改變泛型嵌套層數(shù)調(diào)用的話(比如將?U?帶入?T),只需要通過?rd.xml?指定一下用到的類型即可解決;但是對于前后嵌套層數(shù)不一致的情況,編譯器在編譯時并不知道你到底會展開多少層代碼(NativeAOT 編譯器需要在編譯時展開所有的泛型并為涉及到的所有的方法和類型生成代碼),于是會無限的生成用于?T、U<T>、U<U<T>>... 的代碼,最終導(dǎo)致無法完成編譯。而為什么有 JIT 的情況下不存在問題呢?是因?yàn)榭梢愿鶕?jù)?bar?這個條件在運(yùn)行時按需產(chǎn)生類型和生成代碼。

我曾經(jīng)為 ReactvieX 和 Entity Framework Core 修復(fù)過類似的問題,如果想要了解詳情的話可以參考:

  • Fix infinite recursive generics in CatchScheduler

  • Fix infinite recursive generics

GUI 解決方案

由于短期內(nèi)不支持 COM 和 C++/CLI,意味著 WPF 目前無法經(jīng)過 NativeAOT 編譯為本機(jī)程序,但是好在 WPF 的跨平臺(基于 Skia 自繪)實(shí)現(xiàn)版本 Avalonia 完全不需要 COM,也不包含我上述列出的已知問題,因此今天就已經(jīng)能夠使用它開發(fā)跨平臺的 UI 程序。

由于 0.10.0 版本做了大量優(yōu)化,并引入了編譯時綁定,性能有極大的提升,并且所有動畫都以 60fps 呈現(xiàn),還自帶一套 Fluent Design 的主題庫,體驗(yàn)非常舒適。我經(jīng)過嘗試之后,將自己的可視化通用旅行商問題解算器應(yīng)用使用 NativeAOT 編譯后得到了一個 40mb 大小的應(yīng)用程序(無需運(yùn)行時),可以瞬間啟動且運(yùn)行時內(nèi)存占用不到 20mb,什么才是小而美(戰(zhàn)術(shù)后仰)。

左側(cè)是一個包含接近 70 萬個節(jié)點(diǎn)的折線圖,可以 60 fps 的體驗(yàn)(其實(shí)可以更高,但對于桌面 GUI 應(yīng)用來說 60 fps 渲染是一個默認(rèn)的設(shè)定)隨意滑動、縮放和跟蹤點(diǎn),完全不帶一點(diǎn)卡頓(某 WebGL 實(shí)現(xiàn)的 echart 這時候早已經(jīng)停止了思考)。

Web 解決方案

自然,ASP.NET?Core 是支持 NativeAOT 的(MVC 中的 View 暫時除外),而 Entity Framework Core 由于使用了含泛型的默認(rèn)接口方法實(shí)現(xiàn)暫時不支持 NativeAOT,隨著 NativeAOT 編譯器和庫的更新會解決。

至于重度依賴運(yùn)行時織入 IL 的 Dapper,可能永遠(yuǎn)也不會支持 NativeAOT,畢竟熊掌和魚不可兼得。

當(dāng)然,通過 Source Generator 將動態(tài)生成代碼轉(zhuǎn)為靜態(tài)生成代碼不失為一種解決方案。

不過對于?ASP.NET?Core,有一點(diǎn)需要注意:該框架通過反射程序集加載 Controller,因此代碼路徑中沒有直接引用 Controller 類型的代碼,編譯時所有的 Controller 都會被剪裁掉導(dǎo)致訪問所有的 API 都是 404。這一個問題同樣也是通過編寫?rd.xml?告知編譯器保留類型來解決。

我將自己的一個沒有使用 ORM,只是使用?Microsoft.Data.Sqlite?的用于人員管理的 Web 服務(wù)經(jīng)過 NativeAOT 編譯,得到了一個 30mb 的程序,運(yùn)行后瞬間就能提供服務(wù),內(nèi)存占用只需要 20mb,且首次請求只需要 0.7ms,體驗(yàn)非常的棒。這意味著在云原生環(huán)境下,尤其是擴(kuò)容時,新建節(jié)點(diǎn)中的應(yīng)用可以在極短時間內(nèi)(一秒都不到)啟動并投入使用,而不是都啟動不久了還在等健康檢查的響應(yīng)。預(yù)熱是什么?不存在的!

總結(jié)和展望

毫無疑問,NativeAOT 將能極大的改善 .NET 程序的啟動速度和運(yùn)行性能,并自帶反破解屬性,真正做到 C# 的編寫效率,C++ 的運(yùn)行效率。在 .NET 5 的今天這套工具鏈其實(shí)發(fā)展?fàn)顩r已經(jīng)較為成熟了,想用的話已經(jīng)可以提前體驗(yàn),國外其實(shí)已經(jīng)有使用這套工具鏈上線生產(chǎn)項(xiàng)目的例子了。

.NET NativeAOT 目前還在不斷探索各種可能性,其中一個我認(rèn)為比較有趣的是:

在 NativeAOT 編譯中,先將 IL 借助 RyuJIT 編譯到 LLVM IR,這個過程會對代碼進(jìn)行 IL 特有模式相關(guān)的優(yōu)化;然后將 LLVM IR 編譯到原生二進(jìn)制程序,這個過程將會通過 LLVM 進(jìn)行進(jìn)一步的優(yōu)化,使得編譯后的體積更小、運(yùn)行時性能更強(qiáng)。

先前的之前編譯到 LLVM IR 的實(shí)驗(yàn) LLILC 的問題在于直接 target 到 LLVM IR 導(dǎo)致 RyuJIT 針對 IL 特定模式的優(yōu)化缺失。而新的實(shí)驗(yàn)當(dāng)中,RyuJIT 作為“中端”,做好針對 IL 特定模式的優(yōu)化后再送到 LLVM,避免了該不足之處。

未來 .NET NativeAOT 技術(shù)同樣會被帶到移動平臺和瀏覽器(WebAssembly)上,對于這套技術(shù)以后的發(fā)展我也會長期關(guān)注和跟進(jìn)。

最后,希望 .NET 平臺越來越好。

總結(jié)

以上是生活随笔為你收集整理的通过 .NET NativeAOT 实现用户体验升级的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。