Welcome to My Blog!
I’m so glad you’re here! Thank you for taking the time to explore my first blog.
This is a space where I’ll share my thoughts, experiences and insights on topics I’m passionate about.
Happy reading!
Is there any difference?
As simple as looping may seem, I've noticed that many people have differing opinions and expectations. I would also like to share a more advanced approach.
For benchmarking, I used BenchmarkDotNet (more about this library in one of the upcoming blogs).
It’s important to note that the tests were done in .NET 8, results may vary in other versions.
Microsoft is improving and optimizing its methods and that should be kept in mind.
The five most popular loops you might encounter in .NET are: For, Foreach, and ForEach.
I also decided to include While and Do While loops, because although I rarely see them, I’m sure most people have experience with them.
Additionally, to see how these methods scale, I used the Params attribute.
Test Results:
| Method | Size | Mean | Error | StdDev | Allocated |
|--------- |--------- |-------------:|-----------:|-----------:|----------:|
| While | 100 | 53.24 ns | 0.650 ns | 0.608 ns | - |
| DoWhile | 100 | 57.75 ns | 0.947 ns | 0.886 ns | - |
| For | 100 | 51.47 ns | 1.041 ns | 1.069 ns | - |
| Foreach | 100 | 57.55 ns | 0.944 ns | 0.883 ns | - |
| ForEach | 100 | 159.05 ns | 3.230 ns | 3.720 ns | 88 B |
| Span | 100 | 35.66 ns | 0.400 ns | 0.354 ns | - |
| While | 10000 | 4,945.75 ns | 57.107 ns | 53.418 ns | - |
| DoWhile | 10000 | 4,933.57 ns | 57.123 ns | 50.638 ns | - |
| For | 10000 | 4,996.44 ns | 57.466 ns | 53.754 ns | - |
| Foreach | 10000 | 5,022.52 ns | 55.088 ns | 43.009 ns | - |
| ForEach | 10000 | 12,865.97 ns | 166.771 ns | 155.998 ns | 88 B |
| Span | 10000 | 2,431.47 ns | 44.842 ns | 41.945 ns | - |
| While | 1000000 | 468,287 ns | 4,283 ns | 3,577 ns | - |
| DoWhile | 1000000 | 538,470 ns | 8,877 ns | 8,304 ns | - |
| For | 1000000 | 477,916 ns | 8,949 ns | 8,371 ns | - |
| Foreach | 1000000 | 552,669 ns | 9,157 ns | 8,565 ns | - |
| ForEach | 1000000 | 1,415,655 ns | 23,614 ns | 25,267 ns | 88 B |
From the test results, it can be observed that each approach is approximately equally fast except for one.
ForEach is more than three times slower compared to the others and is also the only one that consumes memory. Honestly, I didn't expect one approach to be so much worse than the others.
However, there is a less common approach that can greatly enhance performance.
Looping using span:
public string Span()
{
var response = string.Empty;
var size = _items.Count;
var span = CollectionsMarshal.AsSpan(_items);
for (var i = 0; i < size; i++)
{
response = span[i];
}
return response;
}Final Test results:
| Method | Size | Mean | Error | StdDev | Allocated |
|--------- |--------- |-------------:|-----------:|-----------:|----------:|
| While | 100 | 53.24 ns | 0.650 ns | 0.608 ns | - |
| DoWhile | 100 | 57.75 ns | 0.947 ns | 0.886 ns | - |
| For | 100 | 51.47 ns | 1.041 ns | 1.069 ns | - |
| Foreach | 100 | 57.55 ns | 0.944 ns | 0.883 ns | - |
| ForEach | 100 | 159.05 ns | 3.230 ns | 3.720 ns | 88 B |
| Span | 100 | 35.66 ns | 0.400 ns | 0.354 ns | - |
| While | 10000 | 4,945.75 ns | 57.107 ns | 53.418 ns | - |
| DoWhile | 10000 | 4,933.57 ns | 57.123 ns | 50.638 ns | - |
| For | 10000 | 4,996.44 ns | 57.466 ns | 53.754 ns | - |
| Foreach | 10000 | 5,022.52 ns | 55.088 ns | 43.009 ns | - |
| ForEach | 10000 | 12,865.97 ns | 166.771 ns | 155.998 ns | 88 B |
| Span | 10000 | 2,431.47 ns | 44.842 ns | 41.945 ns | - |
| While | 1000000 | 468,287 ns | 4,283 ns | 3,577 ns | - |
| DoWhile | 1000000 | 538,470 ns | 8,877 ns | 8,304 ns | - |
| For | 1000000 | 477,916 ns | 8,949 ns | 8,371 ns | - |
| Foreach | 1000000 | 552,669 ns | 9,157 ns | 8,565 ns | - |
| ForEach | 1000000 | 1,415,655 ns | 23,614 ns | 25,267 ns | 88 B |
| Span | 1000000 | 264,530 ns | 4,272 ns | 3,787 ns | - |
Conclusion
As you can see, using span is almost twice as fast as the second fastest approach from today’s test.
Span is a phenomenal, especially if performance is critical, and we will also talk more about it in the upcoming blogs.
However, should we always use span because it's the fastest?
Honestly, I wouldn’t.
I think if performance isn’t crucial for you, it’s better to stick to for/foreach loops, especially since using span can be tricky, and if misused, it may lead to unpredictable behavior.
If you want to conduct additional testing, maybe with different types or simply take a look, you can find the source code here:
Source CodeMaybe you'll come across a use case where ForEach would be a compelling option.
I hope you enjoyed it and that this blog becomes a good friend to you.
