I heard about the new Span and wrote a little sample appliaction to benchmark the execution times.
public class Program
{
private static int _times = 20;
public static void Main(string[] args)
{
var stringResponse = "0123456789";
var byteResponse = new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
// Benchmark with byte[] and Array.Copy()
var stopWatch = new Stopwatch();
stopWatch.Start();
ParseByteArray(byteResponse);
stopWatch.Stop();
var byteArrayTime = stopWatch.ElapsedMilliseconds;
// Benchmark with Span<byte[]>
stopWatch.Restart();
ParseWithSpanOfByteArray(byteResponse);
stopWatch.Stop();
var spanOfByteArrayTime = stopWatch.ElapsedMilliseconds;
// Benchmark with string and string.SubString()
stopWatch.Restart();
ParseWithString(stringResponse);
stopWatch.Stop();
var stringTime = stopWatch.ElapsedMilliseconds;
// Benchmark with Span<string>
stopWatch.Restart();
ParseWithSpanOfString(stringResponse);
stopWatch.Stop();
var spanStringTime = stopWatch.ElapsedMilliseconds;
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"With byte[] and Array.Copy: {byteArrayTime} ms.");
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine($"With Span<byte[]> and Slice: {spanOfByteArrayTime} ms.");
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"With string and string.SubString: {stringTime} ms.");
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine($"With Span<string>: {spanStringTime} ms.");
Console.ReadKey();
}
private static void ParseWithSpanOfString(string response)
{
var result = 0;
var span = response.AsSpan();
for (var i = 0; i < _times; i++)
{
var firstHalf = span.Slice(0, 5);
var secondHalf = span.Slice(5, 5);
result += firstHalf[0];
result += secondHalf[0];
}
Console.WriteLine(result);
}
private static void ParseWithString(string response)
{
var result = 0;
for (var i = 0; i < _times; i++)
{
var firstHalf = response.Substring(0, 5);
var secondHalf = response.Substring(5, 5);
result += firstHalf[0];
result += secondHalf[0];
}
Console.WriteLine(result);
}
private static void ParseByteArray(byte[] response)
{
var result = 0;
for (var i = 0; i < _times; i++)
{
var firstHalf = new byte[5];
var secondHalf = new byte[5];
Array.Copy(response, firstHalf, 5);
Array.Copy(response, 5, secondHalf, 0, 5);
result += firstHalf[0];
result += secondHalf[0];
}
Console.WriteLine(result);
}
private static void ParseWithSpanOfByteArray(Span<byte> response)
{
var result = 0;
for (var i = 0; i < _times; i++)
{
var firstHalf = response.Slice(0, 5);
var secondHalf = response.Slice(5, 5);
result += firstHalf[0];
result += secondHalf[0];
}
Console.WriteLine(result);
}
What I found out is that the promised performance boost of Span only starts around _times = 10.000.000. I am a little bit disappointed.
Result for _times = 1000:
With byte[] and Array.Copy: 3 ms.
With Span<byte[]> and Slice: 22 ms.
With string and string.SubString: 0 ms.
With Span<string>: 3 ms.
Result for _times = 10.000:
With byte[] and Array.Copy: 4 ms.
With Span<byte[]> and Slice: 23 ms.
With string and string.SubString: 1 ms.
With Span<string>: 3 ms.
Result for _times = 100.000:
With byte[] and Array.Copy: 19 ms.
With Span<byte[]> and Slice: 26 ms.
With string and string.SubString: 5 ms.
With Span<string>: 6 ms.
Result for _times = 1.000.000:
With byte[] and Array.Copy: 166 ms.
With Span<byte[]> and Slice: 121 ms.
With string and string.SubString: 72 ms.
With Span<string>: 30 ms.
Am I doing something wrong or should I still prefer using byte[] and string manipulations when dealing with only a few operations?
[EDIT] As mentioned in the comments I had to use the release mode for my little application. The results are now in favor of Span. Even with _times = 1:
With byte[] and Array.Copy: 3 ms.
With Span<byte[]> and Slice: 1 ms.
With string and string.SubString: 0 ms.
With Span<string>: 2 ms.
Only Span seems to be a bit slower in my case...
[Edit] After a lot of comments I learned that my benchmark made no sense it all and I would need a little more time to get correct results.
I now used BenchmarkDotNet to get my results:
Thanks for all the input!