.NET8极致性能优化AOT
前言
.NET8对于性能的优化是方方面面的,所以AOT预编译机器码也是不例外的。本篇来看下对于AOT的优化。
概述
首先要明确一个概念,.NET里面的AOT它是原生的。什么意思呢?也就是说通过ILC编译器(AOT编译器,参考:.Net 7 新编译器 ILC 简析)编译出来的代码是各个平台上可以直接运行的二进制代码。比如MacOS的二进制,Linux二进制等等。所以称之为原生。
C#源码被ILC编译之后,生成了一个完全原生态代码的可执行文件。在执行的时候不需要JIT来编译任何东西,因为JIT已经在ILC里面被充分利用过了。实际上AOT里面也没有包含JIT。那么它如何优化呢?只能是在ILC里面调用JIT的时候了。所以它这个优化依然依靠JIT。.NET8里面优化AOT的一个典型的例子,就是ASP.NET应用程序在使用AOT的时候表现不错,同时也降低了总成本。
在.NET8里面优化AOT的一个重要的目标就是减少AOT可执行文件的大小,关于这点的效果。我们现在就可以看到
下面创建一个控制台应用程序
dotnet new console -o nativeaotexample -f net7.0
由于上面是通过.NET7.0创建的,我们把这个控制台的csproj更改下
<TargetFramework>net7.0</TargetFramework>
改为
<TargetFrameworks>net7.0;net8.0</TargetFrameworks>
可以轻松的构建.NET7.0或者.NET8.0的程序
继续
把<PropertyGroup>...</PropertyGroup>项中添加如下
<PublishAot>true</PublishAot>编译成AOT文件
下面我们就可以通过dotnet publish发布它了,linux如下:
dotnet publish -f net7.0 -r linux-x64 -c Release
现在它生成了一个.NET7.0版本的独立可执行文件,可通过 ls/dir 输出目录以查看生成的二进制大小
12820K /home/stoub/nativeaotexample/bin/Release/net7.0/linux-x64/publish/nativeaotexample
这个大约是13M左右,我们再来看下.NET8.0
dotnet publish -f net8.0 -r linux-x64 -c Release
生成的可执行文件大小如下:
1536K /home/stoub/nativeaotexample/bin/Release/net8.0/linux-x64/publish/nativeaotexample
1.5M的大小,这个优化的力度不可不大啊。整整优化了将近10倍的体积。这就是.NET8.0的优化魔力。
但是优化的情况远不止如此,比如说我们可以配置csproj使AOT的体积更小
csproj添加如下size表示要生成的AOT大小
<OptimizationPreference>Size</OptimizationPreference>
如果我们不需要全球化代码和数据,需要特定的代码和数据,并且使用不变模式,可以csproj添加如下选项
<InvariantGlobalization>true</InvariantGlobalization>
如果你不想在AOT异常的时候抛出堆栈,那么你也可以在csproj里面添加如下
<StackTraceSupport>false</StackTraceSupport>
重新通过dotnet publish net8.0发布了之后,它的体积还可以继续减小
1248K /home/stoub/nativeaotexample/bin/Release/net8.0/linux-x64/publish/nativeaotexample
再次缩小了0.3M大小。
然而,你以为到此优化就为止了吗?并没有,.NET8不仅对AOT编译器内部进行了改进,而且还对单个库也进行了性能优化和改进。比如HttpClient。
当然除了体积的优化之外,还有其它的优化,比如避免了在读取静态字段时的辅助调用,再比如BenchmarkDotNet 也是支持AOT化的,也就是性能测试上面的支持。我们可以只使用 --runtimes nativeaot7.0 nativeaot8.0,而不使用 --runtimes net7.0 net8.0,如下代码
// dotnet run -c Release -f net7.0 --filter "*" --runtimes nativeaot7.0 nativeaot8.0
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
BenchmarkSwitcher.FromAssembly(typeof(Tests).Assembly).Run(args);
[HideColumns("Error", "StdDev", "Median", "RatioSD")]
public class Tests
{
private static readonly int s_configValue = 42;
[Benchmark]
public int GetConfigValue() => s_configValue;
}
上面代码可以通过如下AOT化运行
dotnet run -c Release -f net7.0 --filter "*" --runtimes nativeaot7.0 nativeaot8.0
BenchmarkDotNet 输出如下
Method | Runtime | Mean | Ratio |
---|---|---|---|
GetConfigValue | NativeAOT 7.0 | 1.1759 ns | 1.000 |
GetConfigValue | NativeAOT 8.0 | 0.0000 ns | 0.000 |
可以看到即使是性能测试的Benchmark,AOT优化也是不放过的。
另外还值得一提的地方就是分层,因为AOT里面没有分层的概念。但是即时编译也就是不是AOT编译的时候,一个方法从tier0提升到tier1,方法里面的静态字段必须被初始化过了。AOT里面添加了一个快速路径检查字段是否初始化,避免一些不必要的开销。
其它的一些改进,比如AOT锁的实现方式。使用了一种混合方式,开始使用轻量级自旋锁,后面升级到使用 System.Threading.Lock 类型,这个应该会在.NET9.0里面释放出来。
欢迎关注公众号(jianghupt),文章首发地。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
C语言操作mysql预处理的封装
mysql预处理的优点在于 1.安全性高.预处理变量用占位符?表示,与sql语句是分别传递给服务器,安全性相对比较高. 2.占用流量低.在sql语句已经发送的情况下,只要发送绑定变量的不同值即可. 然而mysql预处理也有一个很大的缺点,就是大量变量绑定的代码,可读性极差,冗余重复代码很多. 我们思考预处理如何做到扬长避短,将冗余代码不放在mysql预处理封装的代码中,而是放在结构体初始化的文件中.这样在结构体初始化的繁琐要好过预处理时的繁琐. 然而结构体的成员变量如何与预处理的bind关联呢? 答案无非是数组.输入数组关联预处理的绑定参数,输出数组关联预处理的绑定结果. 数组的数据来源是结构体,结构体如何将成员变量交接给数组呢? 于是我们冥思苦想发现这个预处理的封装是系统性的工程.需要借助第三方的一些代码完成任务.比如想要把结构体成员对象存取,最好的办法不外乎是hashmap,对输出结果的返回最通用的结构体不外乎是json.因此需要引入hashmap和json. 这样还需要设计一个场景,存取结构体成员,于是我们想到了数据表的crud通用操作.接下来就是设计各个crud的函数用hash...
- 下一篇
Spark Commiter 深度解读:Apache Spark Native Engine
本文来自网易杭研大数据技术专家、Apache Kyuubi PMC Member、Apache Spark Committer 尤夕多, 内容主要围绕 Apache Spark 与 Native Engine 展开,分享什么是 Native Engine,为什么要做 Native Engine,以及怎么做 Native Engine。 前言 Apache Spark 是基于 JVM 语言开发的分布式计算引擎,其 SQL 单个算子的执行性能已经很长时间没有得到提升,比如 Aggregation,Join 等。我们从 Spark2 迁移升级到 Spark3 的主要性能收益来源是 AQE ,而 AQE 其实是一个优化执行计划以及 Shuffle 数据读取的框架,和算子性能本身没有关系,因此 AQE 的优化效果也是有上限的。而在降本增效的背景下,计算集群资源越来越紧张,在不加机器下的基线保证成为常态,但是计算任务却会越来越多,因此用更底层的语言比如 C,C++,Rust 来实现 Native Engine 加速 Spark SQL 计算性能的需求就出现了。其实在 OLAP 生态里,已经有很多成...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- Windows10,CentOS7,CentOS8安装Nodejs环境
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Hadoop3单机部署,实现最简伪集群
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- CentOS6,CentOS7官方镜像安装Oracle11G
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作