zoukankan      html  css  js  c++  java
  • .NET 5 中的隐藏特性

    前言

    双十一当天 .NET 5 正式发布带来了很多的新特性和改进,个人觉得非常香,并且花了 10 分钟时间就把自己的 4 个 .NET Core 3.1 的项目升级到了 .NET 5,堪称无痛。

    但是,.NET 5 中还有一些没有正式公开的隐藏特性,那么现在就开始介绍吧。

    Crossgen 2

    Crossgen 2 とは

    Crossgen 其实就是众所周知的 ReadyToRun 特性。该功能将你的程序集进行一定程度的 AOT 编译,然后在运行时跟踪热路径对一些方法进行带有更多优化的 JIT 编译,即分层编译,这使得程序集的加载速度大幅提高。

    但是 .NET 5 其实带了 Crossgen 的下一个版本:Crossgen 2。

    Crossgen 2 的代码几乎是从 CoreRT 继承而来,并在此基础上做了很大改进。CoreRT 可以对 .NET 程序集进行完全的原生优化编译,编译出来的东西就是完全 native 的,和 Go 的体验完全一致。

    Crossgen 2 则使用了这套方法,将你的程序集在支持范围之内进行 Native AOT 编译,然后运行时直接加载启动,并根据运行情况再使用 JIT 编译器进行进一步的优化,是一种混合 AOT 策略。

    为什么说在支持范围之内呢?因为 Native AOT 必然对动态加载和 Emit 等特性不友好,但是 Crossgen 2 对于这些地方则直接跳过,并且由于是混合 AOT 方案,运行时依然存留有 JIT,因此这些功能完全不会受到影响。

    使用

    使用方法很简单,在你发布程序的时候加命令行参数 /p:PublishReadyToRun=true /p:PublishReadyToRunUseCrossgen2=true 即可,例如:

    dotnet publish -c Release -r win-x64 /p:PublishReadyToRun=true /p:PublishReadyToRunUseCrossgen2=true
    

    注意

    由于该功能尚未正式发布,并且存在一些已知的问题还没有解决,因此如果要使用的话建议对发布出的程序做好测试。

    另外,.NET 6 将会用 Crossgen 2 代替现有的 Crossgen 1,追求稳定的话可以等到明年再用。

    栈上替换

    栈上替换とは

    栈上替换,即 On Stack Replacement。这个特性允许在运行时,即使一个方法有活跃的栈帧也能直接替换实现。

    因此对于分层 JIT 功能来说,这个特性就允许 JIT 将未经优化的代码直接切换成经过优化的代码,即使被切换的方法存在活跃栈帧也没问题。

    使用

    这是一个运行时特性,需要通过设置两个环境变量来开启:

    bash:

    export COMPlus_TC_QuickJitForLoops=1
    export COMPlus_TC_OnStackReplacement=1
    

    cmd:

    set COMPlus_TC_QuickJitForLoops=1
    set COMPlus_TC_OnStackReplacement=1
    

    pwsh:

    $env:COMPlus_TC_QuickJitForLoops = 1
    $env:COMPlus_TC_OnStackReplacement = 1
    

    注意

    当前仅支持 x64,且目前处于实验性阶段。

    更激进的发布裁剪

    发布裁剪とは

    发布裁剪可以在发布时将没有用到的代码裁剪掉,使得发布出去的程序体积大幅度减小。

    但是 .NET 5 默认的裁剪行为是程序集粒度的,意味着会保留用到了的程序集,哪怕你只用了程序集中的一个方法,整个程序集也会被保留下来。

    但是 .NET 5 提供了一种更为激进的裁剪方式,基于方法粒度进行裁剪。

    开启这个特性之后,如果一个程序集只被调用了一个方法,那裁剪后将只会保留这一个方法,而不是保留整个程序集。

    使用

    使用方法很简单,只需要发布时附带命令行参数 /p:PublishTrimmed=true /p:TrimMode=Link 即可,例如:

    dotnet publish -c Release -r win-x64 /p:PublishTrimmed=true /p:TrimMode=Link
    

    如果因为动态加载需要保留一些方法、类型或者程序集的话,可以按照如下文章内的方法进行配置:

    https://devblogs.microsoft.com/dotnet/customizing-trimming-in-net-core-5/

    注意

    由于这种方法较为激进,请确保发布后进行充分的测试,以免出现因为动态加载导致运行时找不到方法的问题。

    实验性运行时

    .NET 大量的新功能已经转移到专门的实验性运行时仓库进行开发了,例如:

    • NativeAOT:基于 RyuJIT 的完全原生编译
    • NativeAOT-LLVM:使用 LLVM 做代码生成的完全原生编译
    • ManagedQuic:完全 C# 实现的 QUIC 协议
    • Utf8String:UTF-8 字符串类型
    • JsonCodeGen:使用代码生成器的 JSON
    • s390x:.NET 在 s390x 架构的移植
    • FreeBSD:.NET 在 FreeBSD 系统的移植
    • MIPS64:.NET 在 MIPS64 架构的移植
    • RegexSRM:基于微软研究院成果 Symbolic Regex Matcher 的正则表达式实现
    • DllImportGenerator:用于自动生成 P/Invoke 接口的代码生成器

    欢迎前往实验仓库中对应分支进行试用和贡献代码:https://github.com/dotnet/runtimelab

    另外,MIPS64 的移植工作由国内龙芯社区团队完成,并将在 .NET 6 并入官方主线,相关信息在 https://github.com/gsvm/loongson-dotnet

    总结

    .NET 5 有很多的没有公开宣布的特性,其中很多特性都非常棒,虽然没有正式发布的现阶段可能还存在一些问题,后期也可能会有较大的改动,但是感兴趣的读者不妨提前体验一波。

  • 相关阅读:
    阅读心得10:《京东咚咚架构演进 》
    hadoop beginning
    ubuntu docker
    Ubuntu学习——第一篇
    flexsim diary
    apollo 3.0 硬件系统
    这是一份详细的Apollo自动驾驶平台上手指南
    详解百度Apollo感知技术、高精地图和小度车载系统
    Apollo 2.5推基于动态的实时相对地图解决方案
    Apollo在功能安全方面的探索
  • 原文地址:https://www.cnblogs.com/hez2010/p/13963803.html
Copyright © 2011-2022 走看看