Performance - The Fastest Way To Loop Over An Array In Microsoft .NET

Arrays in Microsoft .NET is one of the fastest collections in the framework. I would guess that most developers loop over an array something like this:

var collection = personArray;
for (var index = 0; index < collection.Length; index++) {
    base.Update(collection[index]);
}

or

foreach(var person in collection) {
    base.Update(person);
}

Are either of these two ways to loop over an array the fastest? Well, after you read the rest of this article, I’m sure you will need to do some refactoring to speed up your projects.

Performance - The Fastest Way To Loop Over An Array In Microsoft .NET

As part of my work for the 3rd edition of my book “Rock Your Code: Code & App Performance for Microsoft .NET” (released in January of 2023), I tested every major collection type in .NET and every way to loop over these collections. I hope you pick up a copy since I learned a lot working on this edition, and you will too.

I tested these different ways to loop over a collection:

  • do()
  • do/while()
  • for()
  • foreach()
  • ForEach()
  • For()
  • For(MaxDegreeOfParallelism)
  • ForEach()
  • ForEach(MaxDegreeOfParallelism)
  • ForEachAsync()
  • ForEachAsync(MaxDegreeOfParallelism)

Which one of these ways to loop over a collection do you think is the fastest? First, let’s look at a few of these ways to loop over an array. This is an example of using Parallel.For() with MaxDegreeOfParallelism:

var collection = personArray;
ParallelOptions options = new() {
    MaxDegreeOfParallelism = 6
};
_ = Parallel.For(fromInclusive: 0, toExclusive: collection.Length, parallelOptions: options, body: (index) => {
    base.Update(collection[index]);
});

Benchmark Results

Here are the benchmark results that shows using Parallel.For() for a reference, value and record type.

Performance - The Fastest Way To Loop Over An Array In Microsoft .NET

Here is an example of using Parallel.ForEachAsync().

var collection = _personRecordArray;
await Parallel.ForEachAsync(collection, (person, token) => {
    base.Update(person);
    return new ValueTask();
});

Benchmark Results

Here are the benchmark results that shows using Parallel.ForEachAsync() for a reference, value and record type.

Performance - The Fastest Way To Loop Over An Array In Microsoft .NET

As you can see from these benchmarks, using Parallel.ForEachAsync() is a lot slower than using Parallel.For() (around 6.86 times slower).

So, what is the fastest way to loop over an array? Well, according to my benchmark tests, it can actually vary depending on the type used in the array. If the array contains a reference or value type, then using for() is the clear winner! If the array contains the record type, then using Parallel.For() is the fastest (around 1.13 times faster) Here is an example:

var collection = personRecordArray;
_ = Parallel.For(0, collection.Length, (index) => {
    base.Update(collection[index]);
});

In all of my benchmark tests, value types (structures) loops the slowest when compared to the reference and record type. I recommend to not use them in collections.

Using Spargine to Speed Up Arrays

I am currently making changes to my OSS project Spargine based on the findings in the latest edition of my code performance book. To make processing collections as fast as possible easy, I’m adding extension methods called PerformAction(). Here is how I unit test this method:

var words = RandomData.GenerateWords(count: 10, minLength: 10, maxLength: 100).ToArray();
var sb = new StringBuilder();
words.PerformAction((word) => {
    sb.Append(word);
});
var result = sb.ToString();

This method also verifies there are items in the array to prevent exceptions. I will be using this method from now on when processing arrays because if the .NET team comes out with an even faster way to loop over an array, I can just change the code in PerformAction() and instantly all projects that use it get the performance boost! Code reuse is a good thing! I will revisit these methods whenever I do a major run of my benchmark tests so make sure to keep the Spargine NuGet packages up to date. You can add Spargine to your projects by going here: http://bit.ly/dotNetDaveNuGet.

Summary

Is using for() or Parallel.For() the fastest way to loop over all collection types? No, it is not. Different types used in collections even perform differently, as discussed in this article. So, make sure to benchmark your projects, or pick up a copy of my book “Rock Your Code: Code & App Performance for Microsoft .NET” to learn the fastest way to loop over every major collection type in .NET! If you would like to benchmark your code like I do for my book, please read this article “Benchmark your Code Like dotNetDave”.

Do you have any performance questions about .NET? Please make a comment below. I’d love to hear from you.

 


McCarter Consulting
Software architecture, code & app performance, code quality, Microsoft .NET & mentoring. Available!