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

歡迎訪問 生活随笔!

生活随笔

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

asp.net

.NET 6 数组拷贝性能对比

發布時間:2023/12/4 asp.net 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 .NET 6 数组拷贝性能对比 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文來對比多個不同的方法進行數組拷貝,和測試其性能

測試性能必須采用基準(標準)性能測試方法,否則測試結果不可信。在 dotnet 里面,可以采用?BenchmarkDotNet?進行性能測試。詳細請看?C# 標準性能測試

拷貝某個數組的從某個起始點加上某個長度的數據到另一個數組里面,可選方法有很多,本文僅列舉出使用?for?循環拷貝,和使用 Array.Copy 方法和用 Span 方法進行拷貝進行對比

假定有需要被拷貝的數組是?TestData?其定義如下

static Program(){TestData = new int[1000];for (int i = 0; i < 1000; i++){TestData[i] = i;}}private static readonly int[] TestData;

使用?for?循環拷貝的方法如下

public object CopyByFor(int start, int length){var rawPacketData = TestData;var data = new int[length];for (int localIndex = 0, rawArrayIndex = start; localIndex < data.Length; localIndex++, rawArrayIndex++){data[localIndex] = rawPacketData[rawArrayIndex];}return data;}

以上代碼返回 data 作為 object 僅僅只是為了做性能測試,避免被 dotnet 優化掉

另一個拷貝數組是采用?Array.Copy?拷貝,邏輯如下

public object CopyByArray(int start, int length){var rawPacketData = TestData;var data = new int[length];Array.Copy(rawPacketData,start,data,0, length);return data;}

采用新的 dotnet 提供的 Span 進行拷貝,代碼如下

public object CopyBySpan(int start, int length){var rawPacketData = TestData;var rawArrayStartIndex = start;var data = rawPacketData.AsSpan(rawArrayStartIndex, length).ToArray();return data;}

接著加上一些性能調試輔助邏輯

[Benchmark][ArgumentsSource(nameof(ProvideArguments))]public object CopyByFor(int start, int length){var rawPacketData = TestData;var data = new int[length];for (int localIndex = 0, rawArrayIndex = start; localIndex < data.Length; localIndex++, rawArrayIndex++){data[localIndex] = rawPacketData[rawArrayIndex];}return data;}[Benchmark][ArgumentsSource(nameof(ProvideArguments))]public object CopyByArray(int start, int length){var rawPacketData = TestData;var data = new int[length];Array.Copy(rawPacketData,start,data,0, length);return data;}public IEnumerable<object[]> ProvideArguments(){foreach (var start in new[] { 0, 10, 100 }){foreach (var length in new[] { 10, 20, 100 }){yield return new object[] { start, length };}}}

在我的設備上的測試效果如下

BenchmarkDotNet=v0.13.1, OS=Windows 10.0.19042.1200 (20H2/October2020Update) Intel Core i7-9700K CPU 3.60GHz (Coffee Lake), 1 CPU, 8 logical and 8 physical cores .NET SDK=6.0.100-preview.7.21379.14[Host] : .NET 6.0.0 (6.0.21.37719), X64 RyuJITDefaultJob : .NET 6.0.0 (6.0.21.37719), X64 RyuJIT

可以看到,在對比使用?for?循環拷貝和使用?Array.Copy?拷貝中,使用?Array.Copy?拷貝的性能更好,在拷貝的數組長度越長的時候,使用 Array.Copy 拷貝性能優勢就更好

接下來再加上 Span 的性能比較,如下面代碼

[Benchmark][ArgumentsSource(nameof(ProvideArguments))]public object CopyBySpan(int start, int length){var rawPacketData = TestData;var rawArrayStartIndex = start;var data = rawPacketData.AsSpan(rawArrayStartIndex, length).ToArray();return data;}

性能對比測試如下

可以看到 Span 的性能比?Array.Copy?拷貝性能更強

在 Span 里面,轉換為數組的邏輯如下

[MethodImpl(MethodImplOptions.AggressiveInlining)]public T[] ToArray(){if (_length == 0)return Array.Empty<t>();var destination = new T[_length];Buffer.Memmove(ref MemoryMarshal.GetArrayDataReference(destination), ref _pointer.Value, (nuint)_length);return destination;}

這里使用到的 Buffer 的有黑科技的 Memmove 方法,此方法的實現如下

[MethodImpl(MethodImplOptions.AggressiveInlining)]internal static void Memmove<t>(ref T destination, ref T source, nuint elementCount){if (!RuntimeHelpers.IsReferenceOrContainsReferences<t>()){// Blittable memmoveMemmove(ref Unsafe.As<t, byte="">(ref destination),ref Unsafe.As<t, byte="">(ref source),elementCount * (nuint)Unsafe.SizeOf<t>());}else{// Non-blittable memmoveBulkMoveWithWriteBarrier(ref Unsafe.As<t, byte="">(ref destination),ref Unsafe.As<t, byte="">(ref source),elementCount * (nuint)Unsafe.SizeOf<t>());}}

以上性能測試使用的是 int 數組,剛好能進入 Memmove 的分支,而不是 BulkMoveWithWriteBarrier 這個分支。在里層的 Memmove 方法里面用到了很多黑科技,本文只是用來對比多個方法拷貝數組的性能,黑科技部分就需要大家自己去閱讀 dotnet 的源代碼啦

另外,如果需要做完全的數組的拷貝,數組里面存放的是值類型對象,如 int 類型,那么拷貝整個數組還有另一個可選項是通過?Clone?方法進行拷貝,代碼如下

public object CopyByClone(){var data = (int[]) TestData.Clone();return data;}

使用?Clone?的方法的行為是返回數組的淺表拷貝,也就是說數組里面的元素沒有做深拷貝,只是拷貝數組本身而已。對于值類型來說,就沒有啥問題了

稍微更改一下性能測試,更改的代碼如下

[MemoryDiagnoser]public class Program{static void Main(string[] args){BenchmarkRunner.Run<program>();}static Program(){TestData = new int[1000];for (int i = 0; i < 1000; i++){TestData[i] = i;}}[Benchmark]public object CopyByFor(){var rawPacketData = TestData;var length = TestData.Length;var data = new int[length];for (int localIndex = 0, rawArrayIndex = 0; localIndex < data.Length; localIndex++, rawArrayIndex++){data[localIndex] = rawPacketData[rawArrayIndex];}return data;}[Benchmark]public object CopyByArray(){var length = TestData.Length;var start = 0;var rawPacketData = TestData;var data = new int[length];Array.Copy(rawPacketData,start,data,0, length);return data;}[Benchmark]public object CopyByClone(){var data = (int[]) TestData.Clone();return data;}private static readonly int[] TestData;}

通過下圖可以了解到采用 Clone 方法和采用 Array.Copy 方法的性能差不多,但 Clone 稍微快一點

以上是給 WPF 框架做性能優化時測試的,詳細請看

  • Using?Array.Copy?to make array copy faster in StylusPointCollection by lindexi · Pull Request #5217 · dotnet/wpf

  • Using the?Clone?method to fast clone the array in StylusPoint by lindexi · Pull Request #5218 · dotnet/wpf

特別感謝ThomasGoulet73大佬教我使用 AsSpan 的方法拷貝數組

總結

以上是生活随笔為你收集整理的.NET 6 数组拷贝性能对比的全部內容,希望文章能夠幫你解決所遇到的問題。

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