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 測試也是沒問題的,其他數據庫如果有使用問題可以與我交流。