Optimizing Array Iteration in .NET: A Performance Analysis
Written on
Chapter 1: Introduction to Performance Benchmarking
Recently, I have been examining an older system to explore ways to enhance its performance. While there are numerous approaches to boost efficiency, I aimed to implement minor changes that could collectively lead to significant improvements, without undertaking extensive refactoring which could introduce risks. Although upgrading the entire system would be ideal, these incremental adjustments may be the only viable options for developers.
This exploration has sparked my curiosity about identifying the most effective methods for executing routine tasks. I am gradually compiling a series of evaluations, which may involve contrasting various libraries against native features or directly comparing common tasks. Regardless, this journey promises both valuable insights and enjoyment.
Iterating and Accessing Arrays
Today, I focused on various techniques for iterating through an array. While it may seem straightforward, software engineers frequently work with both lists and arrays in C#, making it worthwhile to address these methods.
A crucial aspect of accurate benchmarking is assigning the array item to a variable. Simply iterating without accessing the value can lead to misleading results. Below are the methods utilized and evaluated with BenchmarkDotNet:
- ForEachArray
- ForEach
- GetEnumerator
- Span
- ForEachTheory
Given the similarities in previous tests, I suspect that the Span methods will emerge as the top performers. Conversely, I anticipate the GetEnumerator method to be the least efficient. I also expect the for loop to perform closely to the Span methods, with foreach trailing slightly behind.
Setup for Benchmarking
Using BenchmarkDotNet to create a console application streamlines the process of running these tests. To cover legacy systems, tests will be conducted in both .NET Framework 4.8 and .NET 6.0, representing the current Long Term Support versions. This dual approach allows for a comparison between older and newer frameworks.
The testing process involves creating an array of strings with two different sizes: 100 and 10,000 elements. The tests will repeatedly iterate through each item until BenchmarkDotNet provides satisfactory results, yielding insights into the most efficient methods for future use.
Methods for Iteration
Next, I developed a method for each array iteration technique that I plan to test. Each method performs a single task to maintain a fair benchmark. Specifically, each method will iterate through the array, access each item, and assign it to a variable. Upon processing all items, the method concludes and logs the time taken for completion.
Results of the Benchmarking
Fortunately, BenchmarkDotNet includes a Rank column to clearly indicate which test iteration performed best. The Mean column allows for straightforward comparisons of runtime across tests. Some methods reveal clear winners, while others show negligible differences.
.NET Framework 4.8 — Iteration Results
Copy| Rank | Method | N | Mean |
.NET 6.0 — Iteration Results
Copy| Rank | Method | N | Mean |
Insights from the Results
.NET Framework 4.8 Insights
Surprisingly, the foreach method emerged as the top performer. Given its poor performance with lists, this outcome was unexpected. It outperformed the for loop in both array sizes. Clearly, if you're using arrays, it's time to refactor your code to utilize foreach instead of Array.ForEach.
.NET 6.0 Insights
In .NET 6.0, the Span foreach methods took the top spot, closely followed by the for, foreach, and Span for methods. This indicates that major refactoring might not be necessary, as the gains are marginal. However, it's advisable to use Span combined with foreach in new code, while Array.ForEach has fallen behind significantly.
Conclusion: Choosing the Right Iterator
Although the differences may not be groundbreaking, the foreach loop stands out as the preferred choice for both .NET 6.0 and .NET Framework 4.8 applications. Just remember to pair it with Span in .NET 6.0 for optimal performance.
Code Repository
All the code used in these benchmarks is open source and available on GitHub. The results were generated through a GitHub Action that runs the benchmark tests, and you can find detailed outputs in that repository.
Explore shocking iterator performance benchmarks in C# and gain insights into efficient coding practices.
Uncover the fastest way to iterate a List in C#, which defies common assumptions.