Performance Tip - For Vs Foreach In Microsoft .NET

Collections are one of the most commonly used types in programming. For any program that uses data, you will be dealing with collections. One of the most common things we do is to iterate over the collection to process the data. There are three main ways to iterate over a collection in .NET…
 

for

 
For is a common statement in many programming languages by using a counter variable to iterate over a collection. 
  1. for (int personCount = 0; personCount < _personCollection.Count - 1; personCount++)  
  2. {  
  3.     var name = _personCollection[personCount].FirstName;  
  4. }  

foreach

 
Foreach was the statement I usually used because it’s cleaner and easier to read.
  1. foreach (var person in _personCollection)  
  2. {  
  3.     var name = person.FirstName;  
  4. }  

foreach with AsParallel()

 
 AsParallel() is part of LINQ and could increase performance if there is a significant load with processing the data.
  1. foreach (var person in _personCollection.AsParallel())  
  2. {  
  3.     var name = person.FirstName;  
  4. }  

Performance

 
I’ve done a lot of benchmarking using for, foreach, and foreachAsParallel() for my book on code performance. I ran the benchmark four times using a collection count of 100, 500, 2000, and 5000. Included in this test is the comparison between .NET Clr 4.7.2 and .NET Core 2.2. Below are the results.
 
Test
Runtime
Collection Count
Mean (ns)
CLR vs CORE Difference
for
Clr 4.7.2
100
108.8216
 
foreach
Clr 4.7.2
100
308.1016
 
foreach AsParallel()
Clr 4.7.2
100
853.7294
 
for
Core 2.2
100
108.3985
-0.4231
foreach
Core 2.2
100
334.339
26.2374
foreach AsParallel()
Core 2.2
100
821.127
-32.60
for
Clr 4.7.2
500
672.2033
 
foreach
Clr 4.7.2
500
1,619.09
 
foreach AsParallel()
Clr 4.7.2
500
3,881.51
 
for
Core 2.2
500
671.033
-1.17
foreach
Core 2.2
500
1,662.23
43.14
foreach AsParallel()
Core 2.2
500
3,626.62
-254.89
for
Clr 4.7.2
2000
3,400.98
 
foreach
Clr 4.7.2
2000
7,615.78
 
foreach AsParallel()
Clr 4.7.2
2000
18,726.19
 
for
Core 2.2
2000
3,422.70
21.72
foreach
Core 2.2
2000
7,444.41
-171.36
foreach AsParallel()
Core 2.2
2000
13,814.03
-4,912.16
for
Clr 4.7.2
5000
10,242.85
 
foreach
Clr 4.7.2
5000
21,524.22
 
foreach AsParallel()
Clr 4.7.2
5000
38,018.76
 
for
Core 2.2
5000
10,330.39
87.54
foreach
Core 2.2
5000
21,290.93
-233.29
foreach AsParallel()
Core 2.2
5000
35,289.98
-2,728.78
 
The test was done using a business object called Person to mimic a real world object. As you can see, using for is around 2-3 times faster than foreach! Wow, I was surprised when I first saw this. The benchmark comparing the .NET Clr 4.7.2 to .NET Core 3 produced similar results.
 
In most tests, .NET Core is faster than the Clr. Moving to .NET Core should be on your team’s roadmap if you aren’t already moving to it.
 

Summary

 
My recommendation is to always use for and avoid foreach. I would also avoid using foreach with AsParallel(), unless there is a load during the processing of the data. In all my open-source projects and any code that I work on in my contracts, I am always using for from now on.
 
Do you have any performance tips when using collections? Please make a comment below.


Recommended Free Ebook
Similar Articles
McCarter Consulting
Software architecture, code & app performance, code quality, Microsoft .NET & mentoring. Available!