Performance: The Fastest Way to Loop Over an Array in Microsoft .NET

Arrays in Microsoft .NET are one of the fastest collections in the framework. I would guess that most developers loop over an array of 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);
}

Is 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. 

The Update() method used in these benchmark tests simulates updating the object. Here is the code:

public void Update(IPerson person)
{
if (person is not null)
{
person.Email = TestEmailLowerCase;
}
}

code-performance-book-cover-e3400.25xAs part of my work for the 3rd edition of my book “Rock Your Code: Code & App Performance for Microsoft .NET” (released in January of 2022), 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 show using Parallel.For() for a reference, value, and record type.

PARALLEL-FOR-MAGDEGREEOFPARALLELISM-2-CHART

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 show using Parallel.ForEachAsync() for a reference, value, and record type.

PARALLEL-FOREACHASYNC-2-CHART

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 use 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 not using 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 method 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.

Pick up any books by David McCarter by going to Amazon.com: http://bit.ly/RockYourCodeBooks

One-Time
Monthly
Yearly

Make a one-time donation

Make a monthly donation

Make a yearly donation

Choose an amount

$5.00
$15.00
$100.00
$5.00
$15.00
$100.00
$5.00
$15.00
$100.00

Or enter a custom amount

$

Your contribution is appreciated.

Your contribution is appreciated.

Your contribution is appreciated.

DonateDonate monthlyDonate yearly

If you liked this article, please buy David a cup of Coffee by going here: https://www.buymeacoffee.com/dotnetdave

© The information in this article is copywritten and cannot be preproduced in any way without express permission from David McCarter.

3 thoughts on “Performance: The Fastest Way to Loop Over an Array in Microsoft .NET

  1. Hey dotNetDave, you can speed up a loop even more if you keep a reference to Length rather than calling it every time.

    var collection = personArray;
    var collectionLength = collection.Length;

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

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.