簡體   English   中英

Array.Clear()與Buffer.BlockCopy()

[英]Array.Clear() vs Buffer.BlockCopy()

背景

我必須非常頻繁地清除固定長度的字節數組(例如: byte[4096] )。

我的問題是尋求適用於通用用法的答案,但對於那些想知道該問題源自何處的人:我目前正在優化我的byte[]對象池。 當它回到游泳池時,我需要擦干凈。


我的問題

在使用Array.Clear()方法清除數組還是使用Buffer.BlockCopy()方法覆蓋空白數組之間,哪種方法效果更好?


樣例代碼

使用Buffer.BlockCopy清除字節數組

Buffer.BlockCopy(blankArray, 0, array, 0, 4096);

- 與 -

使用Array.Clear清除字節數組

Array.Clear(array, 0, 4096);

我的研究

public class Benchmark
{
    const int NUMBER_OF_ITERATIONS = 10000000;
    const int SIZE = 4096;
    static byte[] _blank = new byte[SIZE];
    static byte[] _array = new byte[SIZE];

    public static int ArrayClear()
    {
        for (int i = 0; i < NUMBER_OF_ITERATIONS; i++)
        {
            Array.Clear(_array, 0, SIZE);
        }

        return NUMBER_OF_ITERATIONS;
    }

    public static int BlockCopy()
    {
        for (int i = 0; i < NUMBER_OF_ITERATIONS; i++)
        {
            Buffer.BlockCopy(_blank, 0, _array, 0, SIZE);
        }

        return NUMBER_OF_ITERATIONS;
    }
}

用於運行基准測試的代碼

public class Program
{
    static Func<int>[] labs =
    {
        Benchmark.BlockCopy,
        Benchmark.ArrayClear,
    };

    static void Main(string[] args)
    {
        for (int i = 0; i < labs.Length; i++)
        {
            long counter = 0;
            int[] gcCounters = new int[]
            { 
                GC.CollectionCount(0), 
                GC.CollectionCount(1), 
                GC.CollectionCount(2) 
            };

            Console.WriteLine(labs[i].Method.Name + "()");
            Stopwatch stopwatch = Stopwatch.StartNew(); // start benchmark
            counter = labs[i].Invoke();
            stopwatch.Stop(); // end of benchmark

            DisplayResults(gcCounters, stopwatch, counter);
        }

        Console.Write("\nPress any key to continue...");
        Console.ReadKey();
    }

    static void DisplayResults(int[] gcCounters, Stopwatch stopwatch, long counter)
    {
        Console.WriteLine(
            "Total elapsed time was {0:N2} seconds",
            (stopwatch.Elapsed.TotalMilliseconds / 1000)
        );
        Console.WriteLine(
            "Total garbage collection (generation 0) was {0} collections", 
            (GC.CollectionCount(0) - gcCounters[0]).ToString("N0")
        );
        Console.WriteLine(
            "Total garbage collection (generation 1) was {0:N0} collections", 
            (GC.CollectionCount(1) - gcCounters[1])
        );
        Console.WriteLine(
                "Total garbage collection (generation 2) was {0:N0} collections", 
                (GC.CollectionCount(2) - gcCounters[2])
            );
        if (counter > 0)
        {
            Console.WriteLine(
                "Average processing time per iteration took {0:N2} microseconds", 
                ((double)stopwatch.Elapsed.TotalMilliseconds * 1000 / counter)
            );
        }
    }
}

結果

BlockCopy()結果

 Total elapsed time was 3.22 seconds.
 Total garbage collection (generation 0) was 0 collections.
 Total garbage collection (generation 1) was 0 collections.
 Total garbage collection (generation 2) was 0 collections.
 Average processing time per iteration took 0.32 microseconds.

ArrayClear()結果

 Total elapsed time was 0.90 seconds.
 Total garbage collection (generation 0) was 0 collections.
 Total garbage collection (generation 1) was 0 collections.
 Total garbage collection (generation 2) was 0 collections.
 Average processing time per iteration took 0.09 microseconds.

似乎ArrayClear更快。 我不確定這是否意味着它也會表現更好。

您的研究已經得出正確的結論:在這種特定情況下, Array.Clear()性能優於Buffer.BlockCopy()

基准點網

要運行這樣的基准,請使用BenchmarkDotNet 您的基准可以簡化並可以使用BenchmarkDotNet如下運行:

using System;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;

namespace Experiments
{
    [MemoryDiagnoser]
    public class Test
    {
        const int SIZE = 4096;
        static byte[] _blank = new byte[SIZE];
        static byte[] _array = new byte[SIZE];

        [Benchmark]
        public void ArrayClear()
        {
            Array.Clear(_array, 0, SIZE);
        }

        [Benchmark]
        public void BlockCopy()
        {
            Buffer.BlockCopy(_blank, 0, _array, 0, SIZE);
        }
    }

    public class Program
    {
        static void Main(string[] args)
        {
            BenchmarkRunner.Run<Test>();
        }
    }
}

結果

我在x86和x64下的.NET Framework以及x64下的.NET Core上運行了該基准測試。 以下結果表明,在所有實驗中, Array.Clear()性能都優於Buffer.BlockCopy()

# Clr 4.0.30319.42000, 32bit LegacyJIT-v4.7.2053.0

     Method |        Mean |    StdDev | Allocated |
----------- |------------ |---------- |---------- |
 ArrayClear | 154.6503 ns | 0.0192 ns |       0 B |
  BlockCopy | 655.8208 ns | 0.0939 ns |       0 B |

# Clr 4.0.30319.42000, 64bit RyuJIT-v4.7.2053.0

     Method |        Mean |    StdDev | Allocated |
----------- |------------ |---------- |---------- |
 ArrayClear | 179.2065 ns | 0.0205 ns |       0 B |
  BlockCopy | 320.4117 ns | 0.0380 ns |       0 B |

# .NET Core 4.6.25211.01, 64bit RyuJIT

     Method |        Mean |    StdDev | Allocated |
----------- |------------ |---------- |---------- |
 ArrayClear | 107.5015 ns | 0.0145 ns |       0 B |
  BlockCopy | 221.3139 ns | 0.0449 ns |       0 B |

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM