我必须经常清除固定长度的字节数组(例如:
byte[4096]
)。
我的问题是寻求适用于通用用法的答案,但对于那些想知道这个问题源于何处的人:我目前正在优化byte[]
的对象池。我需要在将它放回池中时将其擦干净。
使用
Array.Clear()
方法清除数组或使用Buffer.BlockCopy()
方法用空白数据覆盖数组, 哪种方法会表现得更好?
使用Buffer.BlockCopy
清除字节数组
Buffer.BlockCopy(blankArray, 0, array, 0, 4096);
- VERSUS -
使用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
更快。我不确定这是否意味着它的表现也更好。
答案 0 :(得分:5)
您的研究可以使您得出正确的结论: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 |