首页 > 其他分享 >.NET8 极致性能优化 AOT

.NET8 极致性能优化 AOT

时间:2023-12-05 13:00:40浏览次数:38  
标签:nativeaotexample Release AOT 极致 NET8 net7.0 dotnet 优化

前言

.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 输出如下

MethodRuntimeMeanRatio
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 里面释放出来。

标签:nativeaotexample,Release,AOT,极致,NET8,net7.0,dotnet,优化
From: https://www.cnblogs.com/lzhdim/p/17876972.html

相关文章

  • .NET8极致性能优化AOT
    前言.NET8对于性能的优化是方方面面的,所以AOT预编译机器码也是不例外的。本篇来看下对于AOT的优化。原文:.NET8极致性能优化AOT详述首先明确一个概念,.NET里面的AOT它是原生的。什么意思呢?也就是说通过ILC编译器(AOT编译器,参考:.Net7新编译器ILC简析)编译出来的代码是各个平......
  • 在NET8中使用简化的 AddJwtBearer 认证
    开发环境系统版本:win10.NETSDK:NET8开发工具:vscode参考引用:使用dotnetuser-jwts管理开发中的JSONWeb令牌注意:以下示例中的端口、token等需替换成你的环境中的信息创建项目运行以下命令来创建一个空的Web项目,并添加Microsoft.AspNetCore.Authentication.JwtBea......
  • .NET8 依赖注入
    依赖注入(DependencyInjection,简称DI)是一种设计模式,用于解耦组件(服务)之间的依赖关系。它通过将依赖关系的创建和管理交给外部容器来实现,而不是在组件(服务)内部直接创建依赖对象。​ 咱就是通过IServiceCollection和IServiceProvider来实现的,他们直接被收入到了runtimelibrari......
  • .NET8 极致性能优化 Non-GC Heap
    前言.NET8里面JIT引入了一个新的机制,叫做Non-GCHeap。JIT可以确保相关对象分配在Non-GCHeap上,该堆像其名称一样,不受GC管理。JIT需要保证这个对象没有被GC引用,并且在这个对象的生命周期内一直是根对象(不会被GC消灭的对象)的状态。原文:.NET8极致性能优化Non-......
  • 一个NET8 AOT编译的辅助项目,让你的任何可执行应用快速部署为服务
    ......
  • .Net8新特性
    本文整理.Net8新特性的使用方法。当前包括:RouteShortCircuitExceptionThrowHelperHttpLoggingMiddleware的改进C#12中的InlineArray特性RouteShortCircuit有些请求,如浏览器会自动请求favicon.ico,这些请求即使很简单,往往也会完整地运行中间件管道,但实际上可能并......
  • .NET8极致性能优化Non-GC Heap
    前言.NET8里面JIT引入了一个新的机制,叫做Non-GCHeap。JIT可以确保相关对象分配在Non-GCHeap上,该堆像其名称一样,不受GC管理。JIT需要保证这个对象没有被GC引用,并且在这个对象的生命周期内一直是根对象(不会被GC消灭的对象)的状态。原文:.NET8极致性能优化Non-GCHeap概述为什......
  • ConfigureAwait in .NET8
    ConfigureAwaitin.NET8ConfigureAwait(true)和ConfigureAwait(false)首先,让我们回顾一下原版ConfigureAwait的语义和历史,它采用了一个名为continueOnCapturedContext的布尔参数。当对任务(Task、Task<T>、ValueTask或ValueTask<T>)执行await操作时,其默认行为是捕获“上......
  • 自研的 Fast.ORM 已全面支持AOT编译
    FastFramework作者Mr-zhong代码改变世界....一、前言FastFramework基于NET6.0封装的轻量级ORM框架支持多种数据库SqlServerOracleMySqlPostgreSqlSqlite优点:体积小、原生支持微软特性、流畅API、使用简单、性能高、模型数据绑定采用Expression、强大的表达式......
  • .NET8:快速集成Rapid.NET三维控件
    .NET8正式版本发布了,AnyCADRapid.NET针对.NET8进行了升级和优化。本文以WPF项目为例介绍在.NET8中使用AnyCADRapid.NET三维控件。1从.NET6升级若之前使用NET6升级到.NET8,升级过程非常简单,升级到AnyCADRapid.NET最新版本后,仅需要更改以下两处:(1).csproj文件<TargetFramewor......