パラメータ付きコマンドを、コマンドとパラメータに分割したい。
byte[]のまま処理するか、ReadOnlySpanとして処理するかで、まあ、ReadOnlySpanの方が速いのだろうど、きちんとベンチマークを取ってみた。
public class BenchTarget
{
public static byte[] SampleBytes = Encoding.UTF8.GetBytes("Command Parameter");
[Benchmark]
public int ByteArraySplitBench()
{
int sum = 0;
for(int i = 0;i<100;i++)
{
(var left, var right) = ByteArraySplit(SampleBytes);
sum += left.Length + right.Length;
}
return sum;
}
public static (byte[] left, byte[] right) ByteArraySplit(byte[] source)
{
byte[] left;
byte[] right;
for (int i = 0; i < source.Length; i++)
{
if (source[i] == (byte)' ')
{
left = new byte[i];
source.AsSpan(0, i).CopyTo(left.AsSpan());
right = new byte[source.Length - i - 1];
source.AsSpan(i + 1).CopyTo(right.AsSpan());
return (left, right);
}
}
left = source;
right = Array.Empty<byte>();
return (left, right);
}
[Benchmark]
public int ReadOnlySpanSplitBench()
{
int sum = 0;
for (int i = 0; i < 100; i++)
{
ReadOnlySpanSplit(SampleBytes, out var left, out var right);
sum += left.Length + right.Length;
}
return sum;
}
public static void ReadOnlySpanSplit(ReadOnlySpan<byte> source, out ReadOnlySpan<byte> left, out ReadOnlySpan<byte> right)
{
for (int i = 0; i < source.Length; i++)
{
if (source[i] == (byte)' ')
{
left = source[0..i];
right = source[(i + 1)..];
return;
}
}
left = source;
right = ReadOnlySpan<byte>.Empty;
}
}
結果
| Method | Mean | Error | StdDev |
|----------------------- |-----------:|---------:|---------:|
| ByteArraySplitBench | 1,721.1 ns | 33.61 ns | 33.01 ns |
| ReadOnlySpanSplitBench | 590.9 ns | 3.22 ns | 2.51 ns |
ReadOnlySpanだと、使い方に制限が付く場合もあるが、やはりbyte[]のnewが起こらないため、かなり速くなる。