繁体   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