前言
.NET8對于性能的優(yōu)化是方方面面的,所以AOT預(yù)編譯機(jī)器碼也是不例外的。本篇來看下對于AOT的優(yōu)化。
概述
首先要明確一個概念,.NET里面的AOT它是原生的。什么意思呢?也就是說通過ILC編譯器(AOT編譯器,參考:.Net 7 新編譯器 ILC 簡析)編譯出來的代碼是各個平臺上可以直接運(yùn)行的二進(jìn)制代碼。比如MacOS的二進(jìn)制,Linux二進(jìn)制等等。所以稱之為原生。
C#源碼被ILC編譯之后,生成了一個完全原生態(tài)代碼的可執(zhí)行文件。在執(zhí)行的時候不需要JIT來編譯任何東西,因為JIT已經(jīng)在ILC里面被充分利用過了。實際上AOT里面也沒有包含JIT。那么它如何優(yōu)化呢?只能是在ILC里面調(diào)用JIT的時候了。所以它這個優(yōu)化依然依靠JIT。.NET8里面優(yōu)化AOT的一個典型的例子,就是ASP.NET應(yīng)用程序在使用AOT的時候表現(xiàn)不錯,同時也降低了總成本。
在.NET8里面優(yōu)化AOT的一個重要的目標(biāo)就是減少AOT可執(zhí)行文件的大小,關(guān)于這點(diǎn)的效果。我們現(xiàn)在就可以看到
下面創(chuàng)建一個控制臺應(yīng)用程序
dotnet new console -o nativeaotexample -f net7.0
由于上面是通過.NET7.0創(chuàng)建的,我們把這個控制臺的csproj更改下
net7.0 改為net7.0;net8.0
可以輕松的構(gòu)建.NET7.0或者.NET8.0的程序
繼續(xù)
把... 項中添加如下true 編譯成AOT文件
下面我們就可以通過dotnet publish發(fā)布它了,linux如下:
dotnet publish -f net7.0 -r linux-x64 -c Release
現(xiàn)在它生成了一個.NET7.0版本的獨(dú)立可執(zhí)行文件,可通過ls/dir 輸出目錄以查看生成的二進(jìn)制大小
12820K /home/stoub/nativeaotexample/bin/Release/net7.0/linux-x64/publish/nativeaotexample
這個大約是13M左右,我們再來看下.NET8.0
dotnet publish -f net8.0 -r linux-x64 -c Release
生成的可執(zhí)行文件大小如下:
1536K/home/stoub/nativeaotexample/bin/Release/net8.0/linux-x64/publish/nativeaotexample
1.5M的大小,這個優(yōu)化的力度不可不大啊。整整優(yōu)化了將近10倍的體積。這就是.NET8.0的優(yōu)化魔力。
但是優(yōu)化的情況遠(yuǎn)不止如此,比如說我們可以配置csproj使AOT的體積更小
csproj添加如下size表示要生成的AOT大小Size
如果我們不需要全球化代碼和數(shù)據(jù),需要特定的代碼和數(shù)據(jù),并且使用不變模式,可以csproj添加如下選項
true
如果你不想在AOT異常的時候拋出堆棧,那么你也可以在csproj里面添加如下
false
重新通過dotnet publish net8.0發(fā)布了之后,它的體積還可以繼續(xù)減小
1248K /home/stoub/nativeaotexample/bin/Release/net8.0/linux-x64/publish/nativeaotexample
再次縮小了0.3M大小。
然而,你以為到此優(yōu)化就為止了嗎?并沒有,.NET8不僅對AOT編譯器內(nèi)部進(jìn)行了改進(jìn),而且還對單個庫也進(jìn)行了性能優(yōu)化和改進(jìn)。比如HttpClient。
當(dāng)然除了體積的優(yōu)化之外,還有其它的優(yōu)化,比如避免了在讀取靜態(tài)字段時的輔助調(diào)用,再比如BenchmarkDotNet 也是支持AOT化的,也就是性能測試上面的支持。我們可以只使用 --runtimes nativeaot7.0 nativeaot8.0,而不使用 --runtimes net7.0 net8.0,如下代碼
// dotnet run -c Release -f net7.0 --filter "*" --runtimes nativeaot7.0 nativeaot8.0 using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Running; BenchmarkSwitcher.FromAssembly(typeof(Tests).Assembly).Run(args); [HideColumns("Error", "StdDev", "Median", "RatioSD")] public class Tests { private static readonly int s_configValue = 42; [Benchmark] public int GetConfigValue() => s_configValue; }
上面代碼可以通過如下AOT化運(yùn)行
dotnet run -c Release -f net7.0 --filter "*" --runtimes nativeaot7.0 nativeaot8.0
BenchmarkDotNet 輸出如下
Method | Runtime | Mean | Ratio |
---|---|---|---|
GetConfigValue | NativeAOT 7.0 | 1.1759 ns | 1.000 |
GetConfigValue | NativeAOT 8.0 | 0.0000 ns | 0.000 |
可以看到即使是性能測試的Benchmark,AOT優(yōu)化也是不放過的。
另外還值得一提的地方就是分層,因為AOT里面沒有分層的概念。但是即時編譯也就是不是AOT編譯的時候,一個方法從tier0提升到tier1,方法里面的靜態(tài)字段必須被初始化過了。AOT里面添加了一個快速路徑檢查字段是否初始化,避免一些不必要的開銷。
其它的一些改進(jìn),比如AOT鎖的實現(xiàn)方式。使用了一種混合方式,開始使用輕量級自旋鎖,后面升級到使用 System.Threading.Lock 類型,這個應(yīng)該會在.NET9.0里面釋放出來。
審核編輯:湯梓紅
-
二進(jìn)制
+關(guān)注
關(guān)注
2文章
795瀏覽量
41643 -
程序
+關(guān)注
關(guān)注
117文章
3785瀏覽量
80999 -
代碼
+關(guān)注
關(guān)注
30文章
4779瀏覽量
68518 -
應(yīng)用程序
+關(guān)注
關(guān)注
37文章
3265瀏覽量
57677 -
編譯器
+關(guān)注
關(guān)注
1文章
1623瀏覽量
49107
原文標(biāo)題:.NET8極致性能優(yōu)化AOT
文章出處:【微信號:OSC開源社區(qū),微信公眾號:OSC開源社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論