<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          .NET 6 數(shù)組拷貝性能對(duì)比

          共 343字,需瀏覽 1分鐘

           ·

          2022-05-28 10:56

          前言


          本文來(lái)對(duì)比多個(gè)不同的方法進(jìn)行數(shù)組拷貝,和測(cè)試其性能


          測(cè)試性能必須采用基準(zhǔn)(標(biāo)準(zhǔn))性能測(cè)試方法,否則測(cè)試結(jié)果不可信。在 dotnet 里面,可以采用 BenchmarkDotNet 進(jìn)行性能測(cè)試。詳細(xì)請(qǐng)看C# 標(biāo)準(zhǔn)性能測(cè)試


          拷貝某個(gè)數(shù)組的從某個(gè)起始點(diǎn)加上某個(gè)長(zhǎng)度的數(shù)據(jù)到另一個(gè)數(shù)組里面,可選方法有很多,本文僅列舉出使用 for 循環(huán)拷貝,和使用 Array.Copy 方法和用 Span 方法進(jìn)行拷貝進(jìn)行對(duì)比


          假定有需要被拷貝的數(shù)組是 TestData 其定義如下

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

          ????????private?static?readonly?int[]?TestData;

          使用 for 循環(huán)拷貝的方法如下

          ????????public?object?CopyByFor(int?start,?int?length)
          ????????{
          ????????????var?rawPacketData?=?TestData;

          ????????????var?data?=?new?int[length];
          ????????????for?(int?localIndex?=?0,?rawArrayIndex?=?start;?localIndex?????????????{
          ????????????????data[localIndex]?=?rawPacketData[rawArrayIndex];
          ????????????}
          ????????????return?data;
          ????????}

          以上代碼返回 data 作為 object 僅僅只是為了做性能測(cè)試,避免被 dotnet 優(yōu)化掉

          另一個(gè)拷貝數(shù)組是采用 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 進(jìn)行拷貝,代碼如下

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

          接著加上一些性能調(diào)試輔助邏輯

          ????????[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[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?};
          ????????????????}
          ????????????}
          ????????}

          在我的設(shè)備上的測(cè)試效果如下

          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?RyuJIT
          ??DefaultJob?:?.NET?6.0.0?(6.0.21.37719),?X64?RyuJIT
          img

          可以看到,在對(duì)比使用 for 循環(huán)拷貝和使用 Array.Copy 拷貝中,使用 Array.Copy 拷貝的性能更好,在拷貝的數(shù)組長(zhǎng)度越長(zhǎng)的時(shí)候,使用 Array.Copy 拷貝性能優(yōu)勢(shì)就更好

          接下來(lái)再加上 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;
          ????????}

          性能對(duì)比測(cè)試如下

          img

          可以看到 Span 的性能比 Array.Copy 拷貝性能更強(qiáng)

          在 Span 里面,轉(zhuǎn)換為數(shù)組的邏輯如下

          ????????[MethodImpl(MethodImplOptions.AggressiveInlining)]
          ????????public?T[]?ToArray()
          ????????{
          ????????????if?(_length?==?0)
          ????????????????return?Array.Empty();

          ????????????var?destination?=?new?T[_length];
          ????????????Buffer.Memmove(ref?MemoryMarshal.GetArrayDataReference(destination),?ref?_pointer.Value,?(nuint)_length);
          ????????????return?destination;
          ????????}

          這里使用到的 Buffer 的有黑科技的 Memmove 方法,此方法的實(shí)現(xiàn)如下

          ????????[MethodImpl(MethodImplOptions.AggressiveInlining)]
          ????????internal?static?void?Memmove(ref?T?destination,?ref?T?source,?nuint?elementCount)
          ????????{
          ????????????if?(!RuntimeHelpers.IsReferenceOrContainsReferences())
          ????????????{
          ????????????????//?Blittable?memmove

          ????????????????Memmove(
          ????????????????????ref?Unsafe.Asbyte="">(ref?destination),
          ????????????????????ref?Unsafe.Asbyte="">(ref?source),
          ????????????????????elementCount?*?(nuint)Unsafe.SizeOf());
          ????????????}
          ????????????else
          ????????????{
          ????????????????//?Non-blittable?memmove
          ????????????????BulkMoveWithWriteBarrier(
          ????????????????????ref?Unsafe.Asbyte="">(ref?destination),
          ????????????????????ref?Unsafe.Asbyte="">(ref?source),
          ????????????????????elementCount?*?(nuint)Unsafe.SizeOf());
          ????????????}
          ????????}

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

          另外,如果需要做完全的數(shù)組的拷貝,數(shù)組里面存放的是值類型對(duì)象,如 int 類型,那么拷貝整個(gè)數(shù)組還有另一個(gè)可選項(xiàng)是通過(guò) Clone 方法進(jìn)行拷貝,代碼如下

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

          使用 Clone 的方法的行為是返回?cái)?shù)組的淺表拷貝,也就是說(shuō)數(shù)組里面的元素沒(méi)有做深拷貝,只是拷貝數(shù)組本身而已。對(duì)于值類型來(lái)說(shuō),就沒(méi)有啥問(wèn)題了

          稍微更改一下性能測(cè)試,更改的代碼如下

          ????[MemoryDiagnoser]
          ????public?class?Program
          ????{
          ????????static?void?Main(string[]?args)
          ????????{
          ????????????BenchmarkRunner.Run();
          ????????}

          ????????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[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;
          ????}

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

          以上是給 WPF 框架做性能優(yōu)化時(shí)測(cè)試。

          轉(zhuǎn)自:lindexi

          鏈接:cnblogs.com/lindexi/p/15216115.html

          瀏覽 31
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产黄色性爱视频 | 青草无码视频在线观看 | 操嫩逼电影网 | 波多野吉衣一二三区乱码 | 天天干天天做 |