日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

.Net 5性能改进

發布時間:2023/12/4 asp.net 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 .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性能:

  • 減少內存分配,就能減少GC回收的次數

  • 減少GC線程掛起的時間.讓工作線程一直在執行任務(說白點就是讓工作線程一直處于干活的狀態)

  • 在.Net 5?GC改進:

  • 在Server GC中增加均衡/平衡機制(Balance),給每個GC線程一樣多的工作量(理論上),每個GC線程執行的時間也是一樣的.避免某個GC線程一直在工作,其他GC線程沒有任務可執行.從而縮短GC線程掛起的時間.?有專門說均衡機制的文章https://devblogs.microsoft.com/dotnet/balancing-work-on-gc-threads/文章?

  • 減少?第0代(gen0)和第1代(gen1)回收次數

  • 減少GC掃描靜態數據和減少使用并發鎖

  • 從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這里有兩個作用:

  • 安全檢查,說C#/VB.Net是安全的語言,第一是編譯的時候,對代碼進行安全檢查.第二是在程序運行的時候,JIT也會進行安全檢查.

  • 生成匯編代碼.

  • 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中通過合并程序集,減少開銷.

    • 更快的數學庫(算法).

  • 改進NaN檢查.生成更小更快的代碼.

  • SSE和AMD64 (Intrinsics為內部函數)?

  • 改進哈希值

    • 更快的加密,如RSA.

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

    • 更快的reflection emit

    • 更快的I/O操作,

    • 更少的內存分配.

    • 減少一些字符串內存分配

    • 減少一些裝箱操作

    • 刪除一些臨時內存分配

    總結

    以上是生活随笔為你收集整理的.Net 5性能改进的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。