AOT 特點
釋出和部署本機 AOT 應用具有以下優勢:
- 最大程度減少磁碟佔用空間:使用本機 AOT 釋出時,將生成一個可執行檔案,其中僅包含支援程式所需的外部依賴項的程式碼。減小的可執行檔案大小可能會導致:
- 較小的容器映像,例如在容器化部署方案中。
- 縮短了較小映像的部署時間。
- 縮短啟動時間:本機 AOT 應用程式可縮短啟動時間,這意味著
- 應用已準備好更快地為請求提供服務。
- 改進了容器業務流程協調程式需要管理從應用的一個版本到另一個版本的轉換的部署。
- 減少記憶體需求:本機 AOT 應用可能會減少記憶體需求,具體由應用執行的工作決定。 減少記憶體消耗可以提高部署密度和可伸縮性。
模板應用在基準測試實驗室中執行,來比較 AOT 已釋出的應用、已修剪的執行時應用和未修剪的執行時應用的效能。下圖顯示了基準測試的結果:
本文內容
2023年11月15日,對.net的開發圈是一個重大的日子,.net 8.0正式版釋出。
那一天,我發表了一篇關於 《.NET8.0 的升級和 AOT 經驗的文章》,整體總結如下:
.NET8.0 AOT 已經到了可用的階段,期待未來版本能改進以下問題:
- 釋出速度變快,目前20-30秒一次實在太慢
- 編譯前檢查錯誤,而不是等釋出後再報執行時錯誤
- 加強除錯,.pdb 100兆++ 為何除錯還都是 c++ 有關內容,不能白瞎了這麼大的除錯檔案啊
- 儘快修復 Console.WriteLine(Enum.GetValues(typeof(TaskInterval))) 這個問題
如果一個全新的 AOT webapi 應用釋出在國產系統上執行,算不算國產信創?
我是開源人:https://github.com/2881099
今天發表 AOT 經驗的續篇和 ORM 有關,肯定會產生一些火藥味,我們們能不能理智用技術的角度看完內容,提示:測試你不是貶低你,OK???
我在 github 上建立一個專門測試 AOT 釋出的開源專案,有興趣可以參與提交程式碼。
https://github.com/2881099/aot_test
FreeSql v3.2.805 + Sqlite
釋出耗時 31.882 秒
orm_freesql.exe ( 16,927KB)
orm_freesql.pdb (123,812KB)
SQLite.Interop.dll ( 1,723KB)
E:\github\aot_test\orm_freesql\bin\Release\net8.0\publish\win-x64>orm_freesql.exe
【FreeSql AOT】開始測試...
Insert 1條 80ms
Select 1條 5ms
Update 1條 86ms
Select 1條 0ms
Delete 1條 74ms
【FreeSql AOT】測試結束.
PS:沒有對 AOT 的支援做專門改進,都是老程式碼。
SqlSugar v5.1.4.117 + Sqlite
程式程式碼設定要求:
StaticConfig.EnableAot = true;
釋出耗時 01:51.002 分鐘
orm_sqlsugar.exe ( 50,133KB)
orm_sqlsugar.pdb (346,412KB)
e_sqlite3 ( 1,597KB)
Microsoft.Data.SqlClient.SNI.dll ( 499KB)
E:\github\aot_test\orm_sqlsugar\bin\Release\net8.0\publish\win-x64>orm_sqlsugar.exe
【SqlSugar AOT】開始測試...
Insert 1條 214ms
Select 1條 29ms
Update 1條 119ms
Select 1條 0ms
Delete 1條 82ms
【SqlSugar AOT】測試結束.
EFCore v8.0 + Sqlite
釋出耗時 50.749 秒
orm_efcore.exe ( 17,410KB)
orm_efcore.pdb (168,788KB)
e_sqlite3 ( 1,652KB)
E:\github\aot_test\orm_efcore\bin\Release\net8.0\publish\win-x64>orm_efcore.exe
【EFCore AOT】開始測試...
Unhandled Exception: System.InvalidOperationException: Model building is not supported when publishing with NativeAOT. Use a compiled model.
at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel(Boolean) + 0x148
at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model() + 0x1c
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite, RuntimeResolverContext, ServiceProviderEngineScope, RuntimeResolverLock) + 0xc2
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite, RuntimeResolverContext) + 0x35
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument) + 0xa4
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite, RuntimeResolverContext) + 0x83
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite, RuntimeResolverContext, ServiceProviderEngineScope, RuntimeResolverLock) + 0xc2
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite, RuntimeResolverContext) + 0x35
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument) + 0xa4
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite, RuntimeResolverContext) + 0x83
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite, RuntimeResolverContext, ServiceProviderEngineScope, RuntimeResolverLock) + 0xc2
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite, RuntimeResolverContext) + 0x35
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument) + 0xa4
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite, RuntimeResolverContext) + 0x83
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite, RuntimeResolverContext, ServiceProviderEngineScope, RuntimeResolverLock) + 0xc2
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite, RuntimeResolverContext) + 0x35
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument) + 0xa4
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite, RuntimeResolverContext) + 0x83
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite, RuntimeResolverContext, ServiceProviderEngineScope, RuntimeResolverLock) + 0xc2
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite, RuntimeResolverContext) + 0x35
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument) + 0xa4
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite, RuntimeResolverContext) + 0x83
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite, RuntimeResolverContext, ServiceProviderEngineScope, RuntimeResolverLock) + 0xc2
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite, RuntimeResolverContext) + 0x35
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument) + 0xa4
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite, ServiceProviderEngineScope) + 0x3d
at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(ServiceIdentifier, ServiceProviderEngineScope) + 0xa3
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type) + 0x42
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider, Type) + 0x50
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider) + 0x29
at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies() + 0x32
at Microsoft.EntityFrameworkCore.DbContext.get_ContextServices() + 0x14f
at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies() + 0x22
at Microsoft.EntityFrameworkCore.DbContext.EntryWithoutDetectChanges[TEntity](TEntity entity) + 0x18
at Microsoft.EntityFrameworkCore.DbContext.SetEntityState[TEntity](TEntity entity, EntityState entityState) + 0x1d
at Program.<Main>$(String[] args) + 0x1da
at orm_efcore!<BaseAddress>+0x7c2ab0
Dapper
Dapper 已經出了新的 DapperAOT 版本,就不測試了,100%支援 AOT。
寫到最後
希望多用技術交流,我寫文章不是自誇 Free 系列開源專案有多流弊,實實在在的花了時間研究,測試透過後才發的文章,分享給大家多一個選擇,讓大家知曉已支援 AOT,僅此而已。
提示:測試你不是貶低你,OK???其他 ORM 可以按 https://github.com/2881099/aot_test 的方式提交測試程式碼,我確實沒時間測試所有 ORM,不是為了比較而比較。
被搶 SEO 關鍵字行為已經不是一次兩次了,確實沒多大意思。
最後上一個統計表格吧,PS:支援 AOT 沒什麼了不起!
測試專案 | 釋出耗時 | 釋出後 .exe 體積 | 釋出後 .pdb 體積 | 透過AOT |
---|---|---|---|---|
FreeSql v3.2.805 + Sqlite | 31.882 秒 | 16,927KB | 123,812KB | 透過 |
SqlSugar v5.1.4.117 + Sqlite | 111.002 秒 | 50,133KB | 346,412KB | 透過 |
EFCore v8.0 + Sqlite | 50.749 | 17,410KB | 168,788KB | 未透過 |
DapperAOT | 未測試(支援) | 未測試(支援) | 未測試(支援) | 透過 |
如果大家對 AOT 有興趣,我後面會持續分享自己的經驗,PS mysql 測試也是沒問題的,其他資料庫如果有使用問題可以與我交流。