.NET8.0 AOT 经验分享 FreeSql/FreeRedis/FreeScheduler 均已通过测试

2023-11-20 15:45

本文主要是介绍.NET8.0 AOT 经验分享 FreeSql/FreeRedis/FreeScheduler 均已通过测试,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

2023年11月15日,对.net的开发圈是一个重大的日子,.net 8.0正式版发布。

圈内已经预热了有半个月有余,性能不断超越,开发体验越来越完美,早在.net 5.0的时候就各种吹风Aot编译,直到6.0 7.0使用仍然比较麻烦,我个人比较期待本次更新的aot体验。

有的群友几个小时都等不了啦,半夜就开始更新预览版,我是等到第二天早上正式布发布才开始的,开机第一件事情下载.net8.0 SDK,随后更新vs2022企业版。


支持开源

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

本文通过我们的开源项目升级,以及AOT试验,记录了整个经验过程。

使用我们开源项目的朋友一般都知道,特点依赖较少(甚至零依赖),每次 .net 新版本发布很轻松就支持了,并且为 AOT 埋下了种子。

第一个要更新的开源项目是FreeRedis,这个项目没有任何外部依赖,本身是支持.net 8.0的,本次维护主要把和测试有关项目类型修改成.net8.0,前后只花了大概十分钟,跑完测试后发布了 FreeRedis 1.2.5

FreeRedis 是 .NETFramework 4.0 及以上 访问 redis-server 的客户端组件

第二个要更新的开源项目是CSRedisCore,大致步骤同上,目前这个项目处于稳定维护阶段,不再增加新功能。

CSRedisCore 是 .NETFramework 4.0 及以上 访问 redis-server 的客户端组件,也是 FreeSql 作者早年发布的 nuget 版本

第三个要更新的开源项目是FreeSql,这个项目比较庞大,解决方案内有50个子项目,由于主项目也是零依赖,所以基本不需要修改就支持.net8.0。最新编译器提示.netcoreapp2.1高风险漏洞的警告,不得已移除了.netcoreapp2.1有关的依赖注入支持,前后大约花了半个小时,测试后发布了 FreeSql 3.2.805

FreeSql 是一款功能强大的对象关系映射(O/RM)组件,支持 .NET Core 2.1+、.NET Framework 4.0+ 以及 Xamarin✨

第四个要更新的项目是FreeScheduler,这是一个纯净版的定时任务框架,依赖较少只花了5分钟测试发布。

FreeScheduler 实现轻量化定时任务调度,支持集群、临时的延时任务和重复循环任务(可持久化),可按秒,每天/每周/每月固定时间,自定义间隔执行,支持 .NET Core 2.1+、.NET Framework 4.0+ 运行环境。

其他几个开源项目稳定且不依赖 .net 版本,所以本次无需维护更新。


测试与支持 FreeRedis aot

下午没事去买了一杯咖啡,到12点钟还睡不着,刷视频刷到一点半还是睡不着,于是想折腾点什么东西,正好.net 8.0 aot特性,测试一下FreeRedis,看看是否支持。

我是直接创建控制台程序测试的,设置成aot发布之后,.csproj 内容如下:

<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><OutputType>Exe</OutputType><TargetFramework>net8.0</TargetFramework><PublishAot>True</PublishAot></PropertyGroup><ItemGroup><PackageReference Include="FreeRedis" Version="1.2.5" /></ItemGroup>
</Project>

发布 aot 需要使用控制台命令:

dotnet publish -r win-x64 -c release

第一次发布失败,提示要安装桌面版C++,于是我重新去官网下载vS2022企业版安装器,运行它点击修改安装,选中桌面版C++进行安装,大概过了15分钟,安装完毕。

如果已经安装过vs2022,在此点击修改

我可怜的C盘,要占4G多

E:\github\FreeRedis\examples\console_net8>dotnet publish -r win-x64 -c release
适用于 .NET MSBuild 版本 17.8.3+195e7f5a3正在确定要还原的项目…所有项目均是最新的,无法还原。console_net8 -> E:\github\FreeRedis\examples\console_net8\bin\release\net8.0\win-x64\console_net8.dllGenerating native code
C:\Users\28810\.nuget\packages\freeredis\1.2.5\lib\netstandard2.0\FreeRedis.dll : warning IL3053: Assembly 'FreeRedis'
produced AOT analysis warnings. [E:\github\FreeRedis\examples\console_net8\console_net8.csproj]
C:\Users\28810\.nuget\packages\freeredis\1.2.5\lib\netstandard2.0\FreeRedis.dll : warning IL2104: Assembly 'FreeRedis'
produced trim warnings. For more information see https://aka.ms/dotnet-illink/libraries [E:\github\FreeRedis\examples\c
onsole_net8\console_net8.csproj]console_net8 -> E:\github\FreeRedis\examples\console_net8\bin\release\net8.0\win-x64\publish\

只要编译成功,发布aot必然会成功,只是会有一些警告。

2023/11/16  13:06         5,637,120 console_net8.exe
2023/11/16  13:06       137,695,232 console_net8.pdb
2023/11/16  04:13           127,268 FreeRedis.pdb

请无视 .pdb 文件,它是调试用途的可以删除,console_net8.exe 只有 5兆大小。

第二次发布后,运行成功了,纯字符串数值之内的操作全部成功。

正当得意之时,redis.AclGetUser 方法抛出了一个新的错误,该方法返回的是一个实体类型 AclGetUserResult,有使用 Activetor.CreateInstance(typeof(AclGetUserResult)),Aot本身是支持这个方法的,错误提示是不支持该方法的对象类型 AclUserResult。

Unhandled Exception: System.MissingMethodException: No parameterless constructor defined for type 'FreeRedis.AclGetUserResult'.at System.ActivatorImplementation.CreateInstance(Type, Boolean) + 0x119at FreeRedis.RespHelper.CreateInstanceGetDefaultValue(Type) + 0x120at FreeRedis.RespHelper.MapToClass[T](Object[], Encoding) + 0x4aat FreeRedis.RedisClient.<>c__DisplayClass457_0.<AclGetUser>b__1(Object[] a, Boolean _) + 0x220at FreeRedis.RedisResult.ThrowOrValue[TValue](Func`3) + 0x58at FreeRedis.RedisClient.PoolingAdapter.<>c__DisplayClass9_0`1.<AdapterCall>b__0() + 0x141at FreeRedis.RedisClient.LogCallCtrl[T](CommandPacket cmd, Func`1 func, Boolean aopBefore, Boolean aopAfter) + 0x3bbat FreeRedis.RedisClient.LogCall[T](CommandPacket cmd, Func`1 func) + 0x63at FreeRedis.RedisClient.PoolingAdapter.AdapterCall[TValue](CommandPacket, Func`2) + 0x9aat console_net8.Program.Main(String[] args) + 0xa4at console_net8!<BaseAddress>+0x2c67f0

于是我系统的去看了官方aot文档,发现文档太过于简陋,反复看了七八遍也没有找到相关的解决内容。不得已扩大了搜索范围,在谷歌搜索关键字 .net aot 花了近一个小时,最终定位的关键字是 rd.xml,配置相当简单,只需要把FreeRedis的类型全部配置即可。

对应的 .csproj 内容如下:

<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><OutputType>Exe</OutputType><TargetFramework>net8.0</TargetFramework><PublishAot>True</PublishAot></PropertyGroup><ItemGroup><RdXmlFile Include="rd.xml" /></ItemGroup><ItemGroup><PackageReference Include="FreeRedis" Version="1.2.5" /></ItemGroup>
</Project>

对应的 rd.xml 内容如下:

<Directives><Application><Assembly Name="FreeRedis"  Dynamic="Required All"></Assembly></Application>
</Directives>

重新发布后,完美的解决所有问题,.exe 文件体积增涨到 7兆。

这多亏当初设计FreeRedis的时候把依赖简单最低,才这么容易支持更多的运行平台。


第二轮aot试验 FreeScheduler

FreeRedis对.net 8.0以及aot的支持完美收官,这个时候已经凌晨三点,咖啡的劲还很足。

我本身对FreeSql Aot是不抱希望的,所以,就去测试FreeScheduler了。

FreeScheduler支持三种存储方式,内存/数据库/redis

基于内存,毫无压力,直接通过测试。(得益于依赖较少)

基于redis,由于FreeRdis通过了aot测试,基本不会有太大的问题,记得设置好rd.xml,顺利通过。

对应的 .csproj 如下:

<Project Sdk="Microsoft.NET.Sdk.Web"><PropertyGroup><TargetFramework>net8.0</TargetFramework><Nullable>enable</Nullable><ImplicitUsings>enable</ImplicitUsings><InvariantGlobalization>true</InvariantGlobalization><PublishAot>true</PublishAot></PropertyGroup><ItemGroup><RdXmlFile Include="rd.xml" /></ItemGroup><ItemGroup><ProjectReference Include="..\..\FreeScheduler\FreeScheduler.csproj" /></ItemGroup>
</Project>

对应的 rd.xml 内容如下:

<Directives><Application><Assembly Name="FreeScheduler"  Dynamic="Required All"></Assembly><Assembly Name="FreeRedis"  Dynamic="Required All"></Assembly></Application>
</Directives>

FreeScheduler还有一个web管理面板功能,抱着尝试的态度试一试,创建.net8.0自带的web API aot项目,把有关代码加到项目的运行,居然能直接通过,太牛逼了,这是我没有想到的。

对应 Program.cs

using FreeRedis;
using FreeScheduler;
using Newtonsoft.Json;var redis = new RedisClient("127.0.0.1,poolsize=10,exitAutoDisposePool=false");
redis.Serialize = obj => JsonConvert.SerializeObject(obj);
redis.Deserialize = (json, type) => JsonConvert.DeserializeObject(json, type);
redis.Notice += (s, e) =>
{if (e.Exception != null)Console.WriteLine(e.Log);
};
Scheduler scheduler = new FreeSchedulerBuilder().OnExecuting(task =>{Console.WriteLine($"[{DateTime.Now.ToString("HH:mm:ss.fff")}] {task.Topic} 被执行");task.Remark("log..");}).UseStorage(redis).Build();
if (Datafeed.GetPage(scheduler, null, null, null, null).Total == 0)
{scheduler.AddTask("[系统预留]清理任务数据", "86400", -1, 3600);scheduler.AddTaskRunOnWeek("(周一)武林大会", "json", -1, "1:12:00:00");scheduler.AddTaskRunOnWeek("(周日)亲子活动", "json", -1, "0:00:00:00");scheduler.AddTaskRunOnWeek("(周六)社交活动", "json", -1, "6:00:00:00");scheduler.AddTaskRunOnMonth("月尾最后一天", "json", -1, "-1:16:00:00");scheduler.AddTaskRunOnMonth("月初第一天", "json", -1, "1:00:00:00");scheduler.AddTask("定时20秒", "json", 10, 20);scheduler.AddTask("测试任务1", "json", new[] { 10, 30, 60, 100, 150, 200 });
}var builder = WebApplication.CreateSlimBuilder(args);builder.Services.AddSingleton(scheduler);var app = builder.Build();
var applicationLifeTime = app.Services.GetService<IHostApplicationLifetime>();
applicationLifeTime.ApplicationStopping.Register(() =>
{scheduler.Dispose();redis.Dispose();
});
app.UseFreeSchedulerUI("/freescheduler/");app.Run();

2023/11/16  04:23               127 appsettings.Development.json
2023/11/16  04:23               151 appsettings.json
2023/11/16  13:34        25,104,384 Examples_FreeScheduler_Net80_aot.exe
2023/11/16  13:34       238,948,352 Examples_FreeScheduler_Net80_aot.pdb
2023/11/16  13:31            31,208 FreeScheduler.pdb

Examples_FreeScheduler_Net80_aot.exe 25兆,流弊了,双击运行它吧~~~~

打开浏览器访问:http://localhost:5000/freescheduler/

FreeScheduler 管理面板

意想不到,连管理面板都支持 AOT,这让我有了继续试验的动力~~~


aot试验意外收获 FreeSql

四点了,还没犯困!

最后抱着必凉的心态尝试终极试验,FreeScheduler使用数据库持久化。

第一次失败,报错在FreeSql内部,这是是有TaskInterval类型不存在,它其实是FreeScheduler程序集的,并且rd.xml已经配置好了,反复折腾仍然报错。

Unhandled Exception: System.NotSupportedException: 'FreeScheduler.TaskInterval[]' is missing native code or metadata. This can happen for code that is not compatible with trimming or AOT. Inspect and fix trimming and AOT related warnings that were generated when the app was published. For more information see https://aka.ms/nativeaot-compatibilityat System.Reflection.Runtime.General.TypeUnifier.WithVerifiedTypeHandle(RuntimeArrayTypeInfo, RuntimeTypeInfo) + 0x54at System.Array.InternalCreate(RuntimeType elementType, Int32 rank, Int32* pLengths, Int32* pLowerBounds) + 0x64at System.Array.CreateInstance(Type elementType, Int32 length) + 0x46at System.RuntimeType.GetEnumValues() + 0x53at FreeSql.Internal.Utils.GetTableByEntity(Type entity, CommonUtils common) + 0x138aat FreeSql.Internal.CommonProvider.CodeFirstProvider.<SyncStructure>b__51_0(CodeFirstProvider.TypeAndName a) + 0x6eat System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext() + 0x3fat System.Linq.Enumerable.WhereEnumerableIterator`1.ToArray() + 0x5cat FreeSql.Internal.CommonProvider.CodeFirstProvider.SyncStructure(CodeFirstProvider.TypeAndName[] objects) + 0xd6at FreeSql.Internal.CommonProvider.CodeFirstProvider.SyncStructure[TEntity]() + 0x6cat FreeScheduler.TaskHandlers.FreeSqlHandler..ctor(IFreeSql fsql) + 0xf0at FreeSchedulerBuilder.Build() + 0x2fat Program.<Main>$(String[] args) + 0x180at Examples_FreeScheduler_Net80_aot!<BaseAddress>+0xca7fc3

从堆栈 GetEnumValues 可以看出是执行 Enum.GetValues 报错,通过不断尝试中的其中一次,在程序开始写了一行:

Console.WriteLine(Enum.GetValues(typeof(TaskInterval)));

重新发布后,又出现另一个错误,大致与上面的相同,只是类型变成了 TaskStatus,同样加上一行代码:

Console.WriteLine(Enum.GetValues(typeof(TaskStatus)));

又出现了另一个错误:

Unhandled Exception: System.InvalidOperationException: The binary operator Equal is not defined for the types 'System.Reflection.Runtime.TypeInfos.NativeFormat.NativeFormatRuntimeNamedTypeInfo' and 'System.Reflection.Runtime.TypeInfos.RuntimeConstructedGenericTypeInfo'.at System.Linq.Expressions.Expression.GetEqualityComparisonOperator(ExpressionType, String, Expression, Expression, Boolean) + 0x26bat System.Linq.Expressions.Expression.Equal(Expression, Expression, Boolean, MethodInfo) + 0x63at FreeSql.Internal.Utils.<GetDataReaderValueBlockExpression>g__LocalFuncGetExpression|65_0(Boolean ignoreArray, Utils.<>c__DisplayClass65_0&) + 0x3916at FreeSql.Internal.Utils.GetDataReaderValueBlockExpression(Type type, Expression value) + 0x18dat FreeSql.Internal.Utils.<>c__DisplayClass66_0.<GetDataReaderValue>b__1(Type valueType2) + 0x68at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey, Func`2) + 0xa4at FreeSql.Internal.Utils.GetDataReaderValue(Type type, Object value) + 0x147at FreeSql.Internal.Utils.GetTableByEntity(Type entity, CommonUtils common) + 0x145cat FreeSql.Internal.CommonProvider.CodeFirstProvider.<SyncStructure>b__51_0(CodeFirstProvider.TypeAndName a) + 0x6eat System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext() + 0x3fat System.Linq.Enumerable.WhereEnumerableIterator`1.ToArray() + 0x5cat FreeSql.Internal.CommonProvider.CodeFirstProvider.SyncStructure(CodeFirstProvider.TypeAndName[] objects) + 0xd6at FreeSql.Internal.CommonProvider.CodeFirstProvider.SyncStructure[TEntity]() + 0x6cat FreeScheduler.TaskHandlers.FreeSqlHandler..ctor(IFreeSql fsql) + 0xf0at FreeSchedulerBuilder.Build() + 0x2fat Program.<Main>$(String[] args) + 0x1a8at Examples_FreeScheduler_Net80_aot!<BaseAddress>+0xca8423

这次使用 vs2022 附加进程的方式进行了调试,深入 FreeSql 内部源码(表达式树)环境,定位到了一行代码:

Expression.Equal(type, Expression.Contrast(Guid?))

把 Guid? 后面的问题去掉后,再次发布。(由于每次发布时间要20-30秒,重试时间成本太高,卡在这个问题已经有半个小时)

2023/11/16  04:23               127 appsettings.Development.json
2023/11/16  04:23               151 appsettings.json
2023/11/16  13:52        29,018,112 Examples_FreeScheduler_Net80_aot.exe
2023/11/16  13:52       238,948,352 Examples_FreeScheduler_Net80_aot.pdb
2023/11/16  13:31            31,208 FreeScheduler.pdb
2021/11/03  01:47         1,763,632 SQLite.Interop.dll

对于一个 web 项目并且包含 bootstrap 有关静态资源文件,.exe 文件只有 29兆太满意了

看到控制台上的 SQL,太惊喜了,成功啦~~~~


最后建议

从 .net6.0 到 .net8.0,我们肉眼看不到变化,实际微软做了很多内部工作,在 aot 使用体验上明显能感知。

有人说信创国产运行,那现在 aot 算什么?

.net8.0 AOT 已经到了可用的阶段,期待未来版本能改进以下问题:

  • 发布速度变快,目前20-30秒一次实在太慢
  • 编译前检查错误,而不是等发布后再报运行时错误
  • 加强调试,.pdb 100兆++ 为何调试还都是 c++ 有关内容,不能白瞎了这么大的调试文件啊
  • 尽快修复 Console.WriteLine(Enum.GetValues(typeof(TaskInterval))) 这个问题

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

Native AOT apps have the following limitations:

  • No dynamic loading, for example, Assembly.LoadFile.
  • No run-time code generation, for example, System.Reflection.Emit.
  • No C++/CLI.
  • Windows: No built-in COM.
  • Requires trimming, which has limitations.
  • Implies compilation into a single file, which has known incompatibilities.
  • Apps include required runtime libraries (just like self-contained apps, increasing their size as compared to framework-dependent apps).
  • System.Linq.Expressions always use their interpreted form, which is slower than run-time generated compiled code.
  • Not all the runtime libraries are fully annotated to be Native AOT compatible. That is, some warnings in the runtime libraries aren’t actionable by end developers.

这篇关于.NET8.0 AOT 经验分享 FreeSql/FreeRedis/FreeScheduler 均已通过测试的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/395700

相关文章

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

性能测试介绍

性能测试是一种测试方法,旨在评估系统、应用程序或组件在现实场景中的性能表现和可靠性。它通常用于衡量系统在不同负载条件下的响应时间、吞吐量、资源利用率、稳定性和可扩展性等关键指标。 为什么要进行性能测试 通过性能测试,可以确定系统是否能够满足预期的性能要求,找出性能瓶颈和潜在的问题,并进行优化和调整。 发现性能瓶颈:性能测试可以帮助发现系统的性能瓶颈,即系统在高负载或高并发情况下可能出现的问题

字节面试 | 如何测试RocketMQ、RocketMQ?

字节面试:RocketMQ是怎么测试的呢? 答: 首先保证消息的消费正确、设计逆向用例,在验证消息内容为空等情况时的消费正确性; 推送大批量MQ,通过Admin控制台查看MQ消费的情况,是否出现消费假死、TPS是否正常等等问题。(上述都是临场发挥,但是RocketMQ真正的测试点,还真的需要探讨) 01 先了解RocketMQ 作为测试也是要简单了解RocketMQ。简单来说,就是一个分

【专题】2024飞行汽车技术全景报告合集PDF分享(附原数据表)

原文链接: https://tecdat.cn/?p=37628 6月16日,小鹏汇天旅航者X2在北京大兴国际机场临空经济区完成首飞,这也是小鹏汇天的产品在京津冀地区进行的首次飞行。小鹏汇天方面还表示,公司准备量产,并计划今年四季度开启预售小鹏汇天分体式飞行汽车,探索分体式飞行汽车城际通勤。阅读原文,获取专题报告合集全文,解锁文末271份飞行汽车相关行业研究报告。 据悉,业内人士对飞行汽车行业

【测试】输入正确用户名和密码,点击登录没有响应的可能性原因

目录 一、前端问题 1. 界面交互问题 2. 输入数据校验问题 二、网络问题 1. 网络连接中断 2. 代理设置问题 三、后端问题 1. 服务器故障 2. 数据库问题 3. 权限问题: 四、其他问题 1. 缓存问题 2. 第三方服务问题 3. 配置问题 一、前端问题 1. 界面交互问题 登录按钮的点击事件未正确绑定,导致点击后无法触发登录操作。 页面可能存在

业务中14个需要进行A/B测试的时刻[信息图]

在本指南中,我们将全面了解有关 A/B测试 的所有内容。 我们将介绍不同类型的A/B测试,如何有效地规划和启动测试,如何评估测试是否成功,您应该关注哪些指标,多年来我们发现的常见错误等等。 什么是A/B测试? A/B测试(有时称为“分割测试”)是一种实验类型,其中您创建两种或多种内容变体——如登录页面、电子邮件或广告——并将它们显示给不同的受众群体,以查看哪一种效果最好。 本质上,A/B测

java常用面试题-基础知识分享

什么是Java? Java是一种高级编程语言,旨在提供跨平台的解决方案。它是一种面向对象的语言,具有简单、结构化、可移植、可靠、安全等特点。 Java的主要特点是什么? Java的主要特点包括: 简单性:Java的语法相对简单,易于学习和使用。面向对象:Java是一种完全面向对象的语言,支持封装、继承和多态。跨平台性:Java的程序可以在不同的操作系统上运行,称为"Write once,

分享5款免费录屏的工具,搞定网课不怕错过!

虽然现在学生们不怎么上网课, 但是对于上班族或者是没有办法到学校参加课程的人来说,网课还是很重要的,今天,我就来跟大家分享一下我用过的几款录屏软件=,看看它们在录制网课时的表现如何。 福昕录屏大师 网址:https://www.foxitsoftware.cn/REC/ 这款软件给我的第一印象就是界面简洁,操作起来很直观。它支持全屏录制,也支持区域录制,这对于我这种需要同时录制PPT和老师讲

Verybot之OpenCV应用一:安装与图像采集测试

在Verybot上安装OpenCV是很简单的,只需要执行:         sudo apt-get update         sudo apt-get install libopencv-dev         sudo apt-get install python-opencv         下面就对安装好的OpenCV进行一下测试,编写一个通过USB摄像头采

【干货分享】基于SSM的体育场管理系统的开题报告(附源码下载地址)

中秋送好礼 中秋佳节将至,祝福大家中秋快乐,阖家幸福。本期免费分享毕业设计作品:《基于SSM的体育场管理系统》。 基于SSM的体育场管理系统的开题报告 一、课题背景与意义 随着全民健身理念的深入人心,体育场已成为广大师生和社区居民进行体育锻炼的重要场所。然而,传统的体育场管理方式存在诸多问题,如资源分配不均、预约流程繁琐、数据统计不准确等,严重影响了体育场的使用效率和用户体验。