前言

.NET8对于性能的优化是方方面面的,所以AOT预编译机器码也是不例外的。本篇来看下对于AOT的优化。原文:.NET8极致性能优化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

原文:.NET8极致性能优化AOT

文章公众号(jianghupt)首发,欢迎关注

.NET8极致性能优化AOT的更多相关文章

  1. MIS性能优化常见问题与方案(辅助项目组性能优化的总结贴)

    最近帮忙公司的几个项目组进行了不同方面的性能优化,发现几个项目都出现了一些共性的问题.这里写一篇文章,总结一下这几类问题,以及其对应的解决方案.方便其它项目组参考.   常见问题一:打开页面非常慢,有 ...

  2. 【前端构建】WebPack实例与前端性能优化

    计划把微信的文章也搬一份上来. 这篇主要介绍一下我在玩Webpack过程中的心得.通过实例介绍WebPack的安装,插件使用及加载策略.感受构建工具给前端优化工作带来的便利. 壹 | Fisrt 曾几 ...

  3. Android应用性能优化(转)

    人类大脑与眼睛对一个画面的连贯性感知其实是有一个界限的,譬如我们看电影会觉得画面很自然连贯(帧率为24fps),用手机当然也需要感知屏幕操作的连贯性(尤其是动画过度),所以Android索性就把达到这 ...

  4. Web前端性能优化教程09:图像和Cookie优化

    本文是Web前端性能优化系列文章中的第九篇,主要讲述内容:图像和Cookie优化.完整教程可查看:  一. 图像优化 图像基础知识 gif: 适用于动画效果,例如提示的滚动条图案 jpg: 是一种使用 ...

  5. Web前端性能优化教程07:精简JS 移除重复脚本

    本文是Web前端性能优化系列文章中的第七篇,主要讲述内容:精简Javascript代码,以及移出重复脚本.完整教程可查看:  一.精简javascript 基础知识 精简:从javascript代码中 ...

  6. web前端性能优化

    性能优化对于用户体验无疑是非常重要的,下面介绍一些性能优化的方法. 1.减少HTTP请求 http请求越多,那么消耗的时间越多,如果在加上网络很糟糕,那么问题就更多了.且如果网页中的图片.css文件. ...

  7. 一些新的web性能优化技术

    1.IconFont:图标字体,这是近年来新流行的一种以字体代替图片的技术.它可以适应任何分辨率而不会出现图片模糊问题,与图片相比它具有更小的容量,更高的灵活性(像字体一样可以设置图标大小.颜色.透明 ...

  8. Web 前端性能优化准则

    准则01:尽量减少http请求 “只有10%-20%的最终用户响应时间花在接收请求的HTML文档上,剩下的80%-90%时间花在HTML文档所引用的所有组件(图片,script,css,flash等等 ...

  9. 【原/转】UITableview性能优化总结

    UITableView作为ios中使用最频繁的控件之一,其性能优化也是常常要面对的,尤其是当数据量偏大并且设备性能不足时.本文旨在总结tableview的几个性能优化tips,并且随着认识的深入,本文 ...

  10. mysql数据库性能优化(包括SQL,表结构,索引,缓存)

    优化目标减少 IO 次数IO永远是数据库最容易瓶颈的地方,这是由数据库的职责所决定的,大部分数据库操作中超过90%的时间都是 IO 操作所占用的,减少 IO 次数是 SQL 优化中需要第一优先考虑,当 ...

随机推荐

  1. java file I/O流

    一.File的简介:(java.io包) 生活中的文件: (1)文件的作用:持久化(瞬时状态的对立面状态) (1)文件的定义:一堆数据的集合 (2)文件存储的位置:磁盘,硬盘,软盘,U盘等等 计算机中 ...

  2. QTreeView自绘实现酷炫样式

    本篇文章结合笔者的经历,介绍一种通过重写QTreeView绘制事件,使用QPainter来实现好看的列表的方式. 导语 Hi,各位读者朋友,大家好.相信大家在日常的工作中,经常会接触到QTreeVie ...

  3. 如何做一个完美的api接口?

    如何做一个api接口?:我们知道API其实就是应用程序编程接口,可以把它理解为是一种通道,用来和不同软件系统间进行通信,本质上它是预先定义的函数:-api,接口 1 我们知道API其实就是应用程序编程 ...

  4. C# object类型与dynamic类型的使用

    获取动态变化的类型属性 例: var类型的参数a中包含属性Name或Age 获取这个不固定的数据 首先验证a中存在的是什么属性 /// <summary> /// 验证object类型是否 ...

  5. CodeForces-1324D-Pair-of-Topics

    题意 对于两个长度为\(n\)的数组\(a[]\)和\(b[]\),找到有多少对\(i\)和\(j\)\((i<j)\),满足\(a_i+a_j>b_i+b_j\) 分析 首先发现如果\( ...

  6. Redis系列22:Redis 的Pub/Sub能力

    Redis系列1:深刻理解高性能Redis的本质 Redis系列2:数据持久化提高可用性 Redis系列3:高可用之主从架构 Redis系列4:高可用之Sentinel(哨兵模式) Redis系列5: ...

  7. SQL简单使用指南

    SQL简单使用指南 SQL(结构化查询语言)是一种用于管理和操作关系型数据库的标准化语言. 数据库概述 数据库是用于存储和组织数据的结构.它由表(表格)组成,每个表都包含多个列和行.以下是SQL中最常 ...

  8. ATtiny88初体验(七):TWI

    ATtiny88初体验(七):TWI TWI模块介绍 ATtiny88的TWI模块兼容Phillips I2C以及SMBus,支持主从模式,支持7bit地址,最大允许128个不同的从机地址.在多主机模 ...

  9. 产品代码都给你看了,可别再说不会DDD(六):聚合根与资源库

    这是一个讲解DDD落地的文章系列,作者是<实现领域驱动设计>的译者滕云.本文章系列以一个真实的并已成功上线的软件项目--码如云(https://www.mryqr.com)为例,系统性地讲 ...

  10. RPM软件包:Red HatPackage Manager,RPM

    RPM软件包是按照GPL条款发行在各个linux版本上使用. 用途 可以安装.删除.升级.刷新和管理RPM软件包 通过RPM软件包管理能知道软件包包含哪些文件,也能知道系统中的某个文件属于哪个RPM软 ...