.Net 5性能改进

起因

在.Net Core跳过4.0,避免和先.Net Framework 4.0同名,版本号变为5.0,同时也不在叫.Net Core改为.Net 5(统一的叫法),先看看官方对.Net版本规划.

本文主要是根据https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-5/ 翻译而来.不完全翻译.顺序也有所调整.

从CPU平台看.Net 5改进


在.Net 5 开始使用Arm64指令集进行性能优化,这对国产飞腾和华为鲲鹏服务器,在性能上是有很大的提升.在有就是国产龙芯处理器开始在.Net Core 3.1进行支持,不知道在.Net 5正式发布前.龙芯指令集的代码会不会合并到.Net 5代码的主干中.(编者朱:这个可能性是没有了,.NET 6是很有可能的)

从功能上看.Net 5改进


GC

GC对性能的影响还是很大的.是因为GC回收资源的时候会挂起工作线程,只留GC线程清理资源和回收内存,造成程序有短暂的停顿.

如何提高GC性能:

  1. 减少内存分配,就能减少GC回收的次数

  2. 减少GC线程挂起的时间.让工作线程一直在执行任务(说白点就是让工作线程一直处于干活的状态)

在.Net 5 GC改进:

  1. 在Server GC中增加均衡/平衡机制(Balance),给每个GC线程一样多的工作量(理论上),每个GC线程执行的时间也是一样的.避免某个GC线程一直在工作,其他GC线程没有任务可执行.从而缩短GC线程挂起的时间. 有专门说均衡机制的文章https://devblogs.microsoft.com/dotnet/balancing-work-on-gc-threads/文章 

  2. 减少 第0代(gen0)和第1代(gen1)回收次数

  3. 减少GC扫描静态数据和减少使用并发锁

  4. 从CoreCLR(c/c++代码) 部分代码(如Array.Sort)移植到System.Private.Corelib(C#代码),这样的好处,就是代码复用(CoreCLR和Mono共用一个实现),c#代码是安全的(相对于c语言,如数组越界等),可以更好的优化C#代码.

关于GC示例1代码:

using System;
using System.Diagnostics;
using System.Threading;class Program
{public static void Main(){new Thread(() =>{var a = new int[20];while (true) Array.Sort(a);}) { IsBackground = true }.Start();var sw = new Stopwatch();while (true){sw.Restart();for (int i = 0; i < 10; i++){GC.Collect();Thread.Sleep(15);}Console.WriteLine(sw.Elapsed.TotalSeconds);}}
}

关于GC示例2代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Running;namespace dotnet_perf
{public class DoubleSorting : Sorting<double>{protected override double GetNext() => _random.Next();}public class Int32Sorting : Sorting<int>{protected override int GetNext() => _random.Next();}public class StringSorting : Sorting<string>{protected override string GetNext(){var dest = new char[_random.Next(1, 5)];for (int i = 0; i < dest.Length; i++) dest[i] = (char)('a' + _random.Next(26));return new string(dest);}}public abstract class Sorting<T>{protected Random _random;private T[] _orig, _array;[Params(10)]public int Size { get; set; }protected abstract T GetNext();[GlobalSetup]public void Setup(){_random = new Random(42);_orig = Enumerable.Range(0, Size).Select(_ => GetNext()).ToArray();_array = (T[])_orig.Clone();Array.Sort(_array);}[Benchmark]public void Random(){_orig.AsSpan().CopyTo(_array);Array.Sort(_array);}}
}

JIT改进

JIT(即时编译器,也有人称实时编译器).作用就是C#/Vb.Net代码(编译后生成IL代码,CPU是不认识什么是IL代码的),在运行的时候,JIT生成汇编代码(或者叫机器指令),再有CPU去执行.

JIT这里有两个作用:

  1. 安全检查,说C#/VB.Net是安全的语言,第一是编译的时候,对代码进行安全检查.第二是在程序运行的时候,JIT也会进行安全检查.

  2. 生成汇编代码.

JIT对程序的性能也有很大的比重.所以要求JIT生成性能更高,代码更少的指令(通常情况下汇编指令越少,性能越高,但不是绝对的,比如使用CPU自带的指令).

C#和Java跨平台是都有中间语言的存在(.Net的IL和Java的ByteCode),这里的平台指CPU架构,CPU架构分为CISC(复杂指令集,代表为X86)和RISC(精简指令集,代表为ARM和国产龙芯),在JIT将中间语言生成对应的平台的指令.

示例1:

using System;
using BenchmarkDotNet.Attributes;namespace dotnet_perf
{public class TestJit{private B[] _array = new B[42];[Benchmark]public int Ctor() => new Span<B>(_array).Length;}class A{}sealed class B : A{}
}

汇编代码对比:

.NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT

; dotnet_perf.TestJit.Ctor()
;         public int Ctor() => new Span<B>(_array).Length;
;                              ^^^^^^^^^^^^^^^^^^^^^^^^^^push      rdipush      rsisub       rsp,28mov       rsi,[rcx+8]test      rsi,rsijne       short M00_L00xor       eax,eaxjmp       short M00_L01
M00_L00:mov       rcx,rsicall      00007FF884C41F50mov       rdi,raxmov       rcx,7FF82531DEAAcall      CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEcmp       rdi,raxjne       short M00_L02mov       eax,[rsi+8]
M00_L01:add       rsp,28pop       rsipop       rdiret
M00_L02:call      System.ThrowHelper.ThrowArrayTypeMismatchException()int       3
; Total bytes of code 66

.NET Core 5.0.0 (CoreCLR 5.0.20.47505, CoreFX 5.0.20.47505), X64 RyuJIT

; dotnet_perf.TestJit.Ctor()
;         public int Ctor() => new Span<B>(_array).Length;
;                              ^^^^^^^^^^^^^^^^^^^^^^^^^^mov       rax,[rcx+8]test      rax,raxjne       short M00_L00xor       eax,eaxjmp       short M00_L01
M00_L00:mov       eax,[rax+8]
M00_L01:ret
; Total bytes of code 17

从上方的汇编代码对比,发现.Net 5生成的汇编代码更少,从执行时间来看,.Net 5生成的代码性能更高.

Intrinsics(内部函数,也有称内联函数,这里翻译为指令)

Intrinsics为什么这里要翻译为指令,是因为Intrinsics函数都是在指令集,如X86的AVX/SSE等.

说起这个Intrinsics就得说SIMD(Single Instruction Multiple Data,即单指令流多数据流).

代码:

using System.Numerics;
using BenchmarkDotNet.Attributes;namespace App_Pef5
{[DisassemblyDiagnoser(printSource: true)]//[RyuJitX64Job]public class Intrinsics{[Benchmark]public void T1(){double[] op1 = new double[] { 1.0, 2.0, 3.0, 4.0 };double[] op2 = new double[] { 1.0, 2.0, 3.0, 4.0 };double[] result = new double[4];for (int i = 0; i < 10000; i++){var v1 = new Vector<double>(op1, 0);var v2 = new Vector<double>(op2, 0);var v3 = Vector.Add(v1, v2);v3.TryCopyTo(result);}}[Benchmark]public void T2(){double[] op1 = new double[] { 1.0, 2.0, 3.0, 4.0 };double[] op2 = new double[] { 1.0, 2.0, 3.0, 4.0 };double[] result = new double[4];for (int j = 0; j < 10000; j++){for (int i = 0; i < op1.Length; i++){result[i] = op1[i] + op2[i];}}}}
}


T1函数生成汇编代码:

; App_Pef5.Intrinsics.T1()push      rdipush      rsisub       rsp,28vzeroupper
;             double[] op1 = new double[] { 1.0, 2.0, 3.0, 4.0 };
;             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^mov       rcx,offset MT_System.Double[]mov       edx,4call      CORINFO_HELP_NEWARR_1_VCmov       rsi,raxmov       rcx,14C58332BE0vmovdqu   xmm0,xmmword ptr [rcx]vmovdqu   xmmword ptr [rsi+10],xmm0vmovdqu   xmm0,xmmword ptr [rcx+10]vmovdqu   xmmword ptr [rsi+20],xmm0
;             double[] op2 = new double[] { 1.0, 2.0, 3.0, 4.0 };
;             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^mov       rcx,offset MT_System.Double[]mov       edx,4call      CORINFO_HELP_NEWARR_1_VCmov       rdi,raxmov       rcx,14C58332BE0vmovdqu   xmm0,xmmword ptr [rcx]vmovdqu   xmmword ptr [rdi+10],xmm0vmovdqu   xmm0,xmmword ptr [rcx+10]vmovdqu   xmmword ptr [rdi+20],xmm0
;             double[] result = new double[4];
;             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^mov       rcx,offset MT_System.Double[]mov       edx,4call      CORINFO_HELP_NEWARR_1_VC
;             for (int i = 0; i < 10000; i++)
;                  ^^^^^^^^^xor       edx,edx
;                 var v1 = new Vector<double>(op1, 0);
;                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
M00_L00:vmovupd   ymm0,[rsi+10]
;                 var v2 = new Vector<double>(op2, 0);
;                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^vmovupd   ymm1,[rdi+10]vaddpd    ymm0,ymm0,ymm1
;                 v3.TryCopyTo(result);
;                 ^^^^^^^^^^^^^^^^^^^^^lea       rcx,[rax+10]mov       r8d,4cmp       r8d,4jb        short M00_L01vmovupd   [rcx],ymm0
M00_L01:inc       edxcmp       edx,2710jl        short M00_L00vzeroupperadd       rsp,28pop       rsipop       rdiret
; Total bytes of code 189

T2函数生成汇编代码:

; App_Pef5.Intrinsics.T2()push      rdipush      rsisub       rsp,28vzeroupper
;             double[] op1 = new double[] { 1.0, 2.0, 3.0, 4.0 };
;             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^mov       rcx,offset MT_System.Double[]mov       edx,4call      CORINFO_HELP_NEWARR_1_VCmov       rsi,raxmov       rcx,212ECBD2BE0vmovdqu   xmm0,xmmword ptr [rcx]vmovdqu   xmmword ptr [rsi+10],xmm0vmovdqu   xmm0,xmmword ptr [rcx+10]vmovdqu   xmmword ptr [rsi+20],xmm0
;             double[] op2 = new double[] { 1.0, 2.0, 3.0, 4.0 };
;             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^mov       rcx,offset MT_System.Double[]mov       edx,4call      CORINFO_HELP_NEWARR_1_VCmov       rdi,raxmov       rcx,212ECBD2BE0vmovdqu   xmm0,xmmword ptr [rcx]vmovdqu   xmmword ptr [rdi+10],xmm0vmovdqu   xmm0,xmmword ptr [rcx+10]vmovdqu   xmmword ptr [rdi+20],xmm0
;             double[] result = new double[4];
;             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^mov       rcx,offset MT_System.Double[]mov       edx,4call      CORINFO_HELP_NEWARR_1_VC
;             for (int j = 0; j < 10000; j++)
;                  ^^^^^^^^^xor       edx,edx
;                 for (int i = 0; i < op1.Length; i++)
;                      ^^^^^^^^^
M00_L00:xor       ecx,ecx
;                     result[i] = op1[i] + op2[i];
;                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
M00_L01:movsxd    r8,ecxvmovsd    xmm0,qword ptr [rsi+r8*8+10]vaddsd    xmm0,xmm0,qword ptr [rdi+r8*8+10]vmovsd    qword ptr [rax+r8*8+10],xmm0inc       ecxcmp       ecx,4jl        short M00_L01inc       edxcmp       edx,2710jl        short M00_L00add       rsp,28pop       rsipop       rdiret
; Total bytes of code 185

使用intrinsics指令,单次并不会带来性能的提升,需要在多次使用的时候,才能带来更好的性能,因为上面的代码,是我首次使用intrinsics,后面在去了解C/C++中是如何使用的.在去整体对比性能.

从细节上看有哪些改进

  • 更快的加载程序集,在.Net Core时,程序集被拆分的很多且很小的,加载很多很小的是会增加开销,在.Net 5中通过合并程序集,减少开销.

  • 更快的数学库(算法).

  1. 改进NaN检查.生成更小更快的代码.

  2. SSE和AMD64 (Intrinsics为内部函数) 

  3. 改进哈希值

  • 更快的加密,如RSA.

  • 更快的P/Invoke操作,Windows和Linux

  • 更快的reflection emit

  • 更快的I/O操作,

  • 更少的内存分配.

    1. 减少一些字符串内存分配

    2. 减少一些装箱操作

    3. 删除一些临时内存分配

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

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

相关文章

开放数字世界中的复杂图数据挑战 —— 以教育与开源场景为例

摘要&#xff1a;开源开放的数字世界开始成为时代的潮流&#xff0c;云原生、数据中台、智能PRA开始成为数字世界中的新一代中流砥柱。随着第四范式的普遍流行&#xff0c;各个行业中的数字化转型都会带了海量的具有无限关联的复杂图数据。本报告将以教育与开源两个场景为例&am…

在IIS中部署SPA应用,多么痛的领悟!

目前公司的Web项目是SPA应用&#xff0c;采用前后端分离开发&#xff0c;所以有时也会倒腾Vue框架。“前后端应用最终以容器形态、在k8s中部署, 为此我搭建了基于Gitlab flow的Devops流程。在Devops实践中&#xff0c;容器部署成为良方和事实标准。但是在开发和自测阶段&#x…

mysql闪回工具下载_MySQL闪回工具之myflash 和 binlog2sql

实践利用binlog2sql查询两个binlog之间的SQL&#xff1a;必须是两个binlog日志&#xff0c;指定start-file和stop-filebinlog2sql -h127.0.0.1 -P3309 -udba -pxxxxxx -dsakila -t employee --start-filemysql-bin.000112 --stop-filemysql-bin.000113 > /tmp/db.sql利用bin…

MySQL大表优化方案

背景阿里云RDS FOR MySQL&#xff08;MySQL5.7版本&#xff09;数据库业务表每月新增数据量超过千万,随着数据量持续增加,我们业务出现大表慢查询,在业务高峰期主业务表的慢查询需要几十秒严重影响业务方案概述一、数据库设计及索引优化MySQL数据库本身高度灵活&#xff0c;造成…

使用Azure静态Web应用部署Blazor Webassembly应用

上一次演示了如何使用Azure静态web应用部署VUE前端项目&#xff08;使用Azure静态web应用全自动部署VUE站点&#xff09;。我们知道静态web应用支持VUE&#xff0c;react&#xff0c;angular等项目的部署。除了支持这些常见前端框架&#xff0c;静态web应用同样支持微软推出的最…

TIOBE 11 月榜单:Python 挤掉 Java,Java的下跌趋势确立了?

喜欢就关注我们吧&#xff01;TIOBE 公布了 2020 年 11 月的编程语言排行榜。Python 已成功跃居榜单第二名&#xff0c;本月排名率为 12.12%&#xff1b;Java 被挤到第三位&#xff0c;排名率降至 11.68%。自有 TIOBE 榜单以来&#xff0c;C 和 Java 之前一直占据着前两名的位置…

一路踩坑,被迫聊聊 C# 代码调试技巧和远程调试

一&#xff1a;背景 1. 讲故事每次项目预交付的时候&#xff0c;总会遇到各种奇葩的坑&#xff0c;我觉得有必要梳理一下以及如何快速解决的&#xff0c;让后来人避避坑&#xff0c;这篇就聊聊自己的所闻所遇&#xff1a;我去&#xff0c;本地环境代码跑的哧溜&#xff0c;上了…

mysql decimal型转化为float_5分钟搞懂MySQL数据类型之数值型DECIMAL类型

速成指南5分钟搞懂MySQL数据类型之数值型--DECIMAL类型DECIMAL类型的语法&#xff1a;DECIMAL[(M[,D])] [UNSIGNED] [ZEROFILL]。其中M指定的是数字的总位数(精度&#xff0c;最大65&#xff0c;默认值10)&#xff0c;D指定的是小数点后数字的位数(最大30&#xff0c;并且不能大…

Java面试必问JVM调优,那.NET5呢?

JVM调优已经是普通Java工程师的必修课了&#xff0c;而.NET开源快5年了&#xff0c;CLR层面的优化到目前都不多见&#xff0c;甚至常用的性能调优工具都还没玩过。.NET5马上来了&#xff0c;要想在互联网大潮中逆袭&#xff0c;光靠平台是不够的&#xff0c;开发者也得给力才行…

win10新建管理员账户_【经验篇001】Win10专业版如何开启超级管理员账户

关注我们前言介绍我们在使用Win10系统的时候&#xff0c;有时候安装一些特殊的专业类软件&#xff0c;需要系统赋予软件特殊的权限&#xff0c;那就需要使用超级管理员帐户&#xff0c;Win10系统安装时候&#xff0c;Administrator账户默认是禁用的&#xff0c;所以我们就需要开…

SQL Server in Docker - 还原数据库

SQL Server in Docker 还原数据库上一回演示了如果在Docker环境下安装SQL Server(使用Docker运行SQL Server)&#xff0c;这次我们来演示下如何还原一个数据库备份文件到数据库实例上。使用winscp上传bak文件到linux服务器上一回我们启动docker容器的时候使用了-v参数挂账了本地…

Xamarin 从零开始部署 iOS 上的 Walterlv.CloudKeyboard 应用

本文将告诉大家如何从零开始在 iOS 上部署 Walterlv.CloudKeyboard 应用。这个 Walterlv.CloudKeyboard 应用是一个云输入法应用&#xff0c;在 GitHub 完全开源&#xff0c;采用 Xamarin 开发&#xff0c;用途是让手机接收电脑端的打字输入的输入法。因为我没有在 iOS 上找到任…

Win10 Terminal + WSL 2 安装配置指南,精致开发体验

自从 Windows Terminal 正式发布后就再没有用过 Windows 系统自带的终端了。主要是 Terminal 简洁且灵活&#xff0c;更重要的是支持特殊字体&#xff0c;通过一些简单的配置可以使得终端看起来更舒适养眼。自从 Win 10 有了 Linux 子系统&#xff08;WSL&#xff09;&#xff…

mysql数据转储方法_Mysql数据库各种导出导入数据方式的区别(我的理解错误还望指正)...

mysqldump,NAVICAT转储&#xff0c;select * outfile在千级数据&#xff0c;万级&#xff0c;百万级数据下的表现。千级数据mysqldump导出sql文件导出是出了拒绝访问的错误&#xff1b;为对应目录(.sql文件要保存的目录)的对应用户添加(正在使用的用户)添加写入权限即可。mysql…

JetBrains 开发者调查 - 编程语言趋势

几个月前在公众号里发布了 StackOverflow 2020 开发者调查结果&#xff0c;其结果对 .NET Core 很友好。今天我们看看 JetBrains 2017-2020 四年的开发者调查结果统计&#xff0c;JetBrains 是偏 Java 系的&#xff0c;尤其是本家的 Kotlin 语言。 我们看一下在编程语言方面的趋…

mycli mysql_MyCLI :易于使用的 MySQL/MariaDB 客户端

导读MyCLI 是一个易于使用的命令行客户端&#xff0c;可用于受欢迎的数据库管理系统 MySQL、MariaDB 和 Percona&#xff0c;支持自动补全和语法高亮。它是使用 prompt_toolkit库写的&#xff0c;需要 Python 2.7、3.3、3.4、3.5 和 3.6 的支持。MyCLI 还支持通过 SSL 安全连接…

究竟是什么可以比反射还快实现动态调用?

戏精分享 C#表达式树&#xff0c;第一季正式完稿 前不久&#xff0c;我们发布了《只要十步&#xff0c;你就可以应用表达式树来优化动态调用》。观众们普遍反映文章的内容太多复杂不太容易理解。因此&#xff0c;我们以此为契机发布了《戏精分享 C#表达式树》系列视频。现在&am…

BCVP,想真正为社区做努力的开发者们

基于Net/Core&#xff0c;快速搭建 API & SPA 及微服务应用组织BASE NETCORE (VUE) PROJECT TEAM每一个.NET开发者都可以通过自己的开源项目(最好可以配套简单发表些文章)在这里进行分享&#xff0c;BCVP开发者组织的意义就是激发和挖掘更多的作品&#xff0c;可能偏基础&a…

求关系模式r的所有候选码_2_1关系数据库的基本概念

1.关系数据结构单一的数据结构-------关系现实世界中的实体以及实体间各种联系均用关系来表示2.域&#xff1a;一组具有相同数据类型的值的集合。例如&#xff1a;整数实数介于某个取值范围的整数指定长度的字符串集合{“男”&#xff0c;“女”}.............3.笛卡尔积3.1 给…

Docker:恢复对开源项目的无限制访问

喜欢就关注我们吧&#xff01;继宣布针对免费用户的拉速限制声明之后&#xff0c;Docker 现如今又透露了进一步的策略更新&#xff0c;旨在恢复对开源项目的无限制访问。Docker 方面此表示&#xff0c;为了支持开源社区&#xff0c;他们为开源项目制定了一个特殊的计划&#xf…