不安装运行时运行 .NET 程序 - NativeAOT( 二 )

但是如果把代码改成异步,或者说的更直白一点的话,返回值是 Task<T> 类型就会出现问题 。比如把上面的代码使用 Task.FromResult 改造一下,使返回值变成 Task<WeatherForecast[]>
[HttpGet]public async Task<WeatherForecast[]> Get(){var arr = Enumerable.Range(1, 5).Select(index => new WeatherForecast{Date = DateTime.Now.AddDays(index),TemperatureC = Random.Shared.Next(-20, 55),Summary = Summaries[Random.Shared.Next(Summaries.Length)]}).ToArray();var result = await Task.FromResult(arr);return result;}改造的程序进行 AOT 发布后运行,访问对应的接口程序不会有任何报错 , 但是返回值是个空对象的json:
{}尝试修复该问题 , 并没有特别的好办法,目前能够勉强使用的办法是使用System.Text.Json source generator 模式进行序列化:首先编写一个 WeatherForecastContext 类继承 JsonSerializerContext,并且标记为 partial 。为啥要标记为 partial ?因为类的另外部分是 source generator 自动生成的 。
[JsonSerializable(typeof(Task<WeatherForecast[]>))]internal partial class WeatherForecastContext : JsonSerializerContext{}第二步,在配置 services 的时候顺便把 WeatherForecastContext 配置进去 。
builder.Services.AddControllers().AddJsonOptions(options => options.JsonSerializerOptions.AddContext<WeatherForecastContext>());通过以上操作,再次 AOT 发布后运行程序,访问接口,数据是能正确的返回了 。但是有一点小瑕疵是Task对象自身的属性也被序列化出来了 。
{"result": [{"date": "2022-10-08T19:14:26.1801524+08:00","temperatureC": 6,"temperatureF": 42,"summary": "Warm"},{"date": "2022-10-09T19:14:26.1816645+08:00","temperatureC": -9,"temperatureF": 16,"summary": "Bracing"},{"date": "2022-10-10T19:14:26.1816648+08:00","temperatureC": -1,"temperatureF": 31,"summary": "Sweltering"},{"date": "2022-10-11T19:14:26.181665+08:00","temperatureC": -17,"temperatureF": 2,"summary": "Balmy"},{"date": "2022-10-12T19:14:26.1816651+08:00","temperatureC": -16,"temperatureF": 4,"summary": "Freezing"}],"asyncState": null,"creationOptions": 0,"exception": null,"id": 1,"isCanceled": false,"isCompleted": true,"isCompletedSuccessfully": true,"isFaulted": false,"status": 5}桌面程序以上对控制台程序,web 程序进行了测试,接下来顺便对桌面 GUI 程序测试一下吧 。

不安装运行时运行 .NET 程序 - NativeAOT

文章插图
很遗憾 , 不管是 WINFROM 还是 WPF 程序,进行 AOT 发布的时候直接都会报错,提示不支持 。
一些其他限制AOT 发布的程序会有一些限制 , 我们编写的时候需要注意:
  1. No dynamic loading (for example, Assembly.LoadFile)
  2. No runtime code generation (for example, System.Reflection.Emit)
  3. No C++/CLI
  4. No built-in COM (only applies to Windows)
  5. Requires trimming, which has limitations
  6. Implies compilation into a single file, which has known incompatibilities
  7. Apps include required runtime libraries (just like self-contained apps, increasing their size, as compared to framework-dependent apps)
以上是直接复制的英文文档(原文地址在文末),因为英文不是很好 , 不进行翻译了,怕误导大家 。主要需要注意的就是 1,2 两点  , 关于动态加载类库跟动态生成代码的问题 。我想序列化的问题大概也就是出在这里,因为传统的序列化需要大量的使用动态生成代码技术 。
总结通过以上我们对 .NET 上最常用的几种程序进行了 Native AOT 发布的测试 。总体来说控制台跟ASP.NET CORE 项目能用,WINFROM 跟 WPF 不能用 。比较遗憾的有两个点:
  1. ASP.NET COER 在序列化方面貌似还有点小问题 。不知道是不是我环境的问题 , 如果有知道的大神请指点指点
  2. 不支持桌面 GUI 程序 。其实从个人的经验来说,桌面端可能对启动速度更加敏感一点,因为c/s程序经常性的打开关闭、打开关闭,如果启动慢用户是很容易察觉的 。如果桌面程序能支持 AOT,那么能大大改进现在 .NET 程序的启动速度,这对用户体验的提升是非常大的 。服务端的话本身启动一次后就长期运行 , 用户不会时时刻刻感受到启动速度带来的影响 。另外现在 .NET 程序启动本身就不慢,况且还有 R2R 可以选 , 正常在100-200ms之间的启动速度已经对用户体验影响不大了 。所以 AOT 之后的启动速度的优势不是很大 。
另外来说说性能,有同学可能觉得 Native AOT 之后性能会有很大的提升 , 毕竟大家都迷信 Native 速度快嘛 。但是经过大佬们的测试事实上 AOT 之后跟没有 AOT 的代码性能基本在伯仲之间,有些地方甚至不如非 Native 的代码 。为什么?因为非 Native 代码可以进行运行时 JIT 啊,可以在运行时分析代码对热点代码进行二次 JIT 来提升性能,而 Native AOT 之后的代码做不到这点 。

推荐阅读