.NET 8.0 本机 AOT

        在软件开发领域,优化性能和简化效率仍然至关重要。.NET 平台二十年来不断创新,为开发人员提供了构建弹性且高效的软件解决方案的基础架构。

        与本机 AOT提前编译相结合,取得了显着的进步。本文深入研究.NET Native AOT,揭示它的工作原理、优点以及它的各种应用场景。

什么是 .NET 本机 AOT?

        .NET 本机提前 (AOT) 编译是 .NET 平台中的一项前沿进步。通过 AOT,C# 代码将在开发人员计算机上编译为本机代码。这与在运行时将代码编译为本机代码的传统方法形成鲜明对比。

下面的架构说明了这一点。.NET 传统编译涉及两个步骤:

        1、C# 编译生成包含中间语言 (IL)代码的 DLL 文件。这样的 DLL 称为.NET 程序集。
        2、执行 .NET 程序时,.NET 运行时(CLR 公共语言运行时)会加载 .NET 程序集。CLR 的子系统负责将 IL 代码编译为由 CPU 直接执行的本机代码。这个子系统被命名为JIT(Just-In-Time)编译器。它之所以得名是因为它仅在首次调用某个方法时才编译该方法的 IL 代码。


        另一方面,.NET Native AOT 编译由一个步骤组成。在开发人员的机器上将 C# 源代码编译为本机代码。此过程涉及将 C# 代码转换为 IL 代码,然后转换为 Native 代码,形成两步编译过程。但这是一个实现细节。这就是下面架构中 AOT .NET 程序集框呈灰色的原因。

.NET 本机 AOT 的优点
.NET 本机提前 (AOT) 编译带来了一系列优势:

        增强的性能:通过将代码预编译为本机机器指令,.NET Native AOT 显着缩短了启动时间并提高了应用程序的整体性能。运行时期间没有 JIT 编译开销意味着执行速度更快,从而提供更流畅的用户体验。
        简化部署: AOT 编译的应用程序通常会生成具有零或更少依赖项的独立可执行文件。这简化了部署过程,使您可以更轻松地跨各种平台和设备分发应用程序,而无需额外安装或运行时组件。
更小的应用程序大小:通过修剪掉不必要的代码,AOT 可以大大减小应用程序的大小。这不仅节省了存储空间,还优化了应用程序的内存占用,这在移动设备或物联网设备等资源受限的环境中尤其重要。
        增强的知识产权保护: AOT 编译将源代码转换为优化的机器代码,使逆向工程尝试更具挑战性。与可以轻松反编译为原始 C# 代码的 IL 代码相比,生成的本机代码更加混乱且难以破译。这增强了应用程序中嵌入的敏感算法、业务逻辑和专有方法的安全性。

.NET Native AOT 的缺点
AOT 带来的好处不可避免地伴随着某些缺点。他们来了:

        特定于平台的编译: .NET Native AOT 生成特定于平台的本机代码,针对特定的体系结构或操作系统进行定制。例如,与常规 .NET 程序集不同,使用 AOT 在 Windows 上生成的可执行文件无法在 Linux 上运行。
        不支持跨操作系统编译:例如,您无法从 Windows 机器编译 Linux 本机版本,反之亦然。
        部分支持Reflection: Reflection依赖于动态代码生成和运行时类型发现,这与AOT编译代码的预编译和静态性质相冲突。然而,我们将在本文末尾看到,通常的反射用法与 AOT 配合得很好。
        需要 AOT 兼容的依赖项: AOT 编译要求项目中使用的所有库和依赖项都与 AOT 兼容。依赖反射、运行时代码生成或其他动态行为的库可能与 AOT 不兼容,从而可能导致冲突或运行时错误。
        增加构建时间: AOT 编译涉及在构建过程中预先生成本机代码。此附加步骤可以显着增加构建时间,特别是对于具有大量代码库的大型项目或应用程序。
        需要 C++ 桌面开发工具: AOT 只能在安装了这些工具的情况下进行编译,这些工具在您的硬盘上最多可达 7GB。

.NET 本机 AOT 实际应用
        使用 Visual Studio 创建 .NET 本机 AOT Web 应用程序,启动 Visual Studio 2022 v17.8(或更高版本)并选择从模板ASP.NET Core Web API(本机 AOT)创建项目。

        该模板为我们生成一个 .NET 8 ASP.NET Core Web API 应用程序,我们可以看到 .csproj 文件包含<PublishAot>true</PublishAot>。

编译 .NET Web 应用程序
        如果我们编译应用程序,我们可以看到在 .dll 下生成了一个 DLL 文件.\bin\debug\net8.0。此 DLL 是包含 IL 代码的常规 .NET 程序集。我们可以使用 ILSpy 对其进行反编译,如下图所示:

执行.NET Web应用程序
        此时,没有发生AOT编译。C# 代码在不到一秒的时间内就被编译为 IL 代码。.NET Web 应用程序可以按原样执行:

使用 .NET Native AOT 编译 Web 应用程序
        要使用 .NET Native AOT 编译 Web 应用程序,您必须dotnet publish 在包管理器控制台中键入:

        这次这个小应用程序的编译花费了 11 秒。我们获得一个大小为 9MB 的可执行文件。该文件无法使用 ILSpy 反编译,因为它不是 .NET 程序集。该文件仅包含本机代码。还生成一个 70MB PDB 文件,将本机代码与源代码链接起来以进行调试。

        可执行文件可以在任何 Windows x64 系统上按原样部署和执行。部署可以更简单吗?我不这么认为!

.NET 本机 AOT 权衡
现在是评估选项的时候了:

        1、一方面,我们在不到一秒的时间内生成了一个可在所有平台上运行的 40KB DLL。但它需要预安装.NET 8.0。
        2、另一方面,我们在 11 秒内编译出一个 9MB 的可执行文件。它可以在任何 Windows x64 系统上运行,无需任何先决条件。此外,这个本机版本的启动速度更快。对于任何足够复杂的 Web 应用程序,我们都可以期待更多的性能提升。
        人们可能会认为 9MB 比 40KB 大得多!但安装 .NET 8.0 需要的磁盘空间远多于 9MB。仅目录C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.0  就有 70MB,而且还有更多东西需要安装。因此 AOT 导致:

3、紧凑的容器镜像在容器化部署设置中特别有用
4、由于图像尺寸较小,部署时间缩短


以下是本文中值得引用的评论:

        这是怎样的前沿进步?在 .NET 平台引入之前的半个世纪里,这种软件的生产方式已经存在。
这是我的答案:因为你同时拥有了两个世界。

        1、一方面,与 C/C++ 相比,现代语言和平台通过运行时带来了许多便利
        2、另一方面,原始的本机可执行文件无需在生产计算机上安装平台。
        暂停一下,你就会意识到这个单一可执行文件有多酷。这 9MB 不仅包含 Web 应用程序代码。但它包含一些 CLR 代码(垃圾收集、库加载……)、常用的 .NET 类型(字符串、整数……)和 API 代码(如WebApplication.CreateSlimBuilder()【WebApplication.CreateSlimBuilder Method (Microsoft.AspNetCore.Builder) | Microsoft Learn】和 JSON 序列化器代码)。

        下面的依赖关系图(通过 NDepend 获得【Visual Studio - Explore existing .net code architecture】)显示了此 Web 应用程序代码及其依赖关系,全部打包在 9MB 位中!

用反射破坏.NET Native AOT?
        我努力尝试用 Reflection 来破坏 .NET Native AOT,但失败了。这是一个好消息,AOT 支持很多 Reflection API。以下是与 AOT 配合使用的代码:

// Reflection usage A
System.Type type = new object().GetType();
System.Reflection.MethodInfo methodInfo = type.GetMethod("ToString");
string str = (string)methodInfo.Invoke("Walk the dog", BindingFlags.Default, null, new object?[0], null);
Console.WriteLine("Reflection usage A:" + str);// Reflection usage B
var listOfString = typeof(List<>).MakeGenericType(new Type[] { typeof(string) });
var list = Activator.CreateInstance(listOfString) as List<string>;
list.Add("hello");
PropertyInfo prop = listOfString.GetProperty("Count");
int count = (int)prop.GetMethod.Invoke(list, new object?[0]);
Console.WriteLine("Reflection usage B:" + count);// Reflection usage C
Assembly assembly = Assembly.GetExecutingAssembly();
Type[] types = assembly.GetTypes();
foreach (Type type1 in types.Take(5)) {Console.WriteLine("Reflection usage C:" + type1.FullName);
}// Reflection usage D
Type unknownType = Type.GetType("System.String");
ParameterExpression param = Expression.Parameter(unknownType, "x");
MethodInfo method = unknownType.GetMethod("ToLower", Type.EmptyTypes);
Expression call = Expression.Call(param, method);
var lambda = Expression.Lambda(call, param).Compile();
var result = lambda.DynamicInvoke("HELLO");
Console.WriteLine("Reflection usage D:" + result);

        我们dotnet publish有时会收到一些警告,但它确实有效!

.NET 8 对本机 AOT 的支持
支持这些

1、Middleware 中间件
2、Minimal APIs 最小 API
3、gRPC 远程过程调用
4、Kestrel HTTP Server
5、Authorization 授权
6、JWT Authentication 认证
7、CORS 跨域资源共享
8、HealthChecks 健康检查
9、OutputCaching 输出缓存
10、RequestDecompression 请求解压
11、ResponseCaching 响应缓存
12、ResponseCompression 响应压缩
13、StaticFiles 静态文件
14、WebSockets
15、ADO.NET
16、PostgreSQL
17、Dapper AOT
18、SQLite

尚不支持这些

1、ASP.NET Core MVC
2、WebAPI
3、SignalR
4、Blazor Server,
5、Razor Pages,
6、Session, Spa
7、Entity Framework Core


结论
        .NET Native AOT 代表了优化 .NET 应用程序的关键一步。这种编译为本机代码的过程可以最大限度地减少运行时对即时 (JIT) 编译的依赖,从而提高性能。由此带来的好处包括更快的执行速度、减少的部署开销以及提高可扩展性的潜力,使其成为提高 .NET 开发领域效率和性能的绝佳选择。

        借助 .NET 8,Native AOT 已经相当成熟,可以在生产中使用。我们当然可以希望微软能够继续改进AOT支持。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/600569.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机进入BIOS - Win/Linux

计算机进入BIOS - Win/Linux 快捷键方法&#xff08;通用&#xff09;Win系统方法Linux系统方法 快捷键方法&#xff08;通用&#xff09; 此方法为通用方法&#xff0c;适用于任何型号的计算机&#xff0c;包括台式机和笔记本&#xff0c;也包括Win系统和Linux系统。 进入BI…

OpenCV-Python(28):基于GrabCut 算法交互式前景提取

目标 GrabCut 算法原理&#xff0c;使用GrabCut 算法提取图像的前景 创建一个交互是程序完成前景提取 介绍 GrabCut算法是一种基于图像分割的算法&#xff0c;用于将图像中的前景物体从背景中准确地分离出来。它是由Carsten Rother等人于2004年提出的。 GrabCut算法的基本思想…

C#,入门教程(10)——常量、变量与命名规则的基础知识

上一篇&#xff1a; C#&#xff0c;入门教程(09)——运算符的基础知识https://blog.csdn.net/beijinghorn/article/details/123908269 C#用于保存计算数据的元素&#xff0c;称为“变量”。 其中一般不改变初值的变量&#xff0c;称为常变量&#xff0c;简称“常量”。 无论…

QT工具栏开始,退出

QT工具栏开始&#xff0c;退出 //初始化场景QMenuBar *bar menuBar();setMenuBar(bar);QMenu *startbar bar->addMenu("开始");QAction * quitAction startbar->addAction("退出");connect(quitAction , &QAction::triggered,[](){this->c…

Pycharm打包程序为exe文件

Pycharm打包程序为exe文件 【一】导入模块pyinstaller 【1】图片说明 【2】文字说明 根据图片顺序执行 首先点击file进入settings界面&#xff0c;在setting界面找到Project下面的Python Interpretor&#xff0c;点击号进行模块的添加在搜索框中输入pyinstaller&#xff0c;…

三、Kubernetes(K8s)入门(一)

视频教程连接k8s 入门到微服务项目实战.xmind链接&#xff1a;https://pan.baidu.com/s/1q04euH7baE8eXNyG3kPPbA 提取码&#xff1a;jej4比较好的笔记 kubectl命令的语法如下&#xff1a; kubectl [command] [type] [name] [flags]comand&#xff1a;指定要对资源执行的操作…

了解单元测试

一&#xff0c;测试分类 1.1 E2E测试&#xff08;end to end端到端测试&#xff09; 属于黑盒测试。 主要通过测试框架&#xff0c;站在用户测试人员的角度&#xff0c;模拟用户的操作进行页面功能的验证&#xff0c;不管内部实现机制&#xff0c;完全模拟浏览器的行为。&am…

任我行CRM系统SmsDataList接口SQL注入漏洞复现 [附POC]

文章目录 任我行CRM系统SmsDataList接口SQL注入漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现0x06 修复建议任我行CRM系统SmsDataList接口SQL注入漏洞复现 [附POC] 0x01 前言 免责声明:请勿利用文章内的相关…

C++《异常》

前言&#xff1a;C有一套独立的异常处理机制,今天就来做详细的介绍try,catch这两个词等 在C语言中处理错误的方式和缺陷有&#xff1a; 返回错误码。 缺陷&#xff1a; 1.错误码不好设置&#xff0c;比如&#xff1a;除0操作&#xff0c;就不好返回错误码。如果返回一个数字&…

Flume基础知识(八):Flume 拓扑结构全解

1. 简单串联 这种模式是将多个 flume 顺序连接起来了&#xff0c;从最初的 source 开始到最终 sink 传送的 目的存储系统。此模式不建议桥接过多的 flume 数量&#xff0c; flume 数量过多不仅会影响传输速 率&#xff0c;而且一旦传输过程中某个节点 flume 宕机&#xff0c;会…

LC 2807. 在链表中插入最大公约数

2807. 在链表中插入最大公约数 难度 &#xff1a; 中等 题目大意&#xff1a; 给你一个链表的头 head &#xff0c;每个结点包含一个整数值。 在相邻结点之间&#xff0c;请你插入一个新的结点&#xff0c;结点值为这两个相邻结点值的 最大公约数 。 请你返回插入之后的链表…

thinkphp学习04-控制器定义

控制器&#xff0c;即 controller&#xff0c;控制器文件存放在 controller 目录下&#xff1b; 如果想改变系统默认的控制器文件目录&#xff0c;可以在 config 下 route.php 配置&#xff1a; 将controller修改为controller123&#xff0c;就会报错&#xff0c;说明这个配置…

Sqlmap参数设置

Sqlmap参数设置 &#x1f388;&#x1f388;&#x1f388;&#x1f388;&#x1f388;&#x1f388;&#x1f388;&#x1f388;&#x1f388;&#x1f388;&#x1f388;&#x1f388;&#x1f388;&#x1f388; --------------------------------------------注意---------…

易图讯便携式三维电子沙盘实战应用系统

便携式三维电子沙盘采用军工加固三防高性能笔记本&#xff0c;具有IP65级防尘防水防摔性能&#xff0c;以大数据、云计算、虚拟现实、物联网、AI等先进技术为支撑&#xff0c;支持高清卫星影像、DEM高程数据、矢量数据、三维模型、倾斜摄像、BIM、点云、城市白模、等高线、标高…

033 - STM32学习笔记 - TIM定时器(一) - 高级定时器

033 - STM32学习笔记 - TIM定时器&#xff08;一&#xff09; - 高级定时器 上节内容学习了基本定时器&#xff0c;其功能比较简单&#xff0c;配置和使用也比较容易&#xff0c;今天在基本定时器的基础上学习一下高级控制定时器的内容。 在F429上一共有两个高级控制定时器和1…

PyTorch|一次画一批图像

想想这样一个场景&#xff0c;我们训练了一个神经网络&#xff0c;输入一些信息&#xff0c;这个网络可以根据信息为我们生成相关图片。 这些图片并不是一张&#xff0c;而是多张&#xff0c;我们想把这些图片一次全部显示出来&#xff0c;而不是一张一张的显示&#xff08;这…

Python蒸发散物理问题(微积分-线性代数-拉普拉斯和傅立叶变换)

使用Python计算解决土壤物理问题的数值。这里数值过程用于求解微分方程&#xff0c;数值方法将微分转化为代数方程&#xff0c;可以使用传统的线性代数方法求解。 Python拉普拉斯变换求解微分方程示例 假设我们有微分方程 y ′ ′ 2 y ′ 16 y cos ⁡ 4 t y^{\prime \pri…

关于unity的组件VerticalLayoutGroup刷新显示不正常的问题

先说明一下我是如何用到&#xff0c;有哪些处理的 用到这个组件基本上都是将列表进行排版操作的&#xff0c;竖着&#xff0c;或者横着&#xff0c;横着用HorizontalLayoutGroup 还有一个和这个组件搭配的组件叫ContentSizeFitter 先说我是怎么发现这个组件不好用的 //本地读取…

中标麒麟文件系统损坏修复

中标麒麟v5.0桌面版本文件系统损坏修复 1.用系统安装光盘启动到如下图界面&#xff0c;关闭或最小化“安装到硬盘”窗口 2.右击打开命令提示符&#xff0c;执行su – root 3.执行如下图命令&#xff0c;找到除swap格式分区的其他分区 4.按照上图显示的格式执行相关命令&#…

【数据结构】二叉搜索(查找/排序)树

一、二叉搜索树基本概念 1、定义 二叉搜索树&#xff0c;又称为二叉排序树&#xff0c;二叉查找树&#xff0c;它满足如下四点性质&#xff1a; 1&#xff09;空树是二叉搜索树&#xff1b; 2&#xff09;若它的左子树不为空&#xff0c;则左子树上所有结点的值均小于它根结…