.NET8.0 AOT 經驗分享 - 專項測試各大 ORM 是否支持

AOT 特點

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

我是開源人:https://github.com/2881099

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章