For vs. Foreach
foreach
loops are really convenient, but are for
loops faster? It’s a simple question, but one that has really wide implications in almost any codebase. Today’s article tests them out to see which is faster for looping over arrays and List
s. Read on to see which is quicker!
Today’s test is simple. It makes an array of object
and a System.Collections.Generic.List
of object
, each with a given length and then loops over them using for
and foreach
loops. Since this takes less than a millisecond, it runs each loop 100,000 times to get a useful result. Here’s the test script:
using System; using System.Collections.Generic; using UnityEngine; public class TestScript : MonoBehaviour { private const int NumIterations = 100000; private string report; void Start() { report = "Size,Array For Time,Array Foreach Time,List For Time,List Foreach Time\n"; var sizes = new []{10,100,1000}; foreach (var size in sizes) { report += Test(size); } } private string Test(int size) { var array = new object[size]; var list = new List<object>(size); list.AddRange(array); var stopwatch = new System.Diagnostics.Stopwatch(); object obj = null; stopwatch.Reset(); stopwatch.Start(); for (var iteration = 0; iteration < NumIterations; ++iteration) { for (int i = 0, len = array.Length; i < len; ++i) { obj = array[i]; } } var arrayForTime = stopwatch.ElapsedMilliseconds; stopwatch.Reset(); stopwatch.Start(); for (var iteration = 0; iteration < NumIterations; ++iteration) { foreach (var cur in array) { } } var arrayForeachTime = stopwatch.ElapsedMilliseconds; stopwatch.Reset(); stopwatch.Start(); for (var iteration = 0; iteration < NumIterations; ++iteration) { for (int i = 0, len = list.Count; i < len; ++i) { obj = list[i]; } } var listForTime = stopwatch.ElapsedMilliseconds; stopwatch.Reset(); stopwatch.Start(); for (var iteration = 0; iteration < NumIterations; ++iteration) { foreach (var cur in list) { } } var listForeachTime = stopwatch.ElapsedMilliseconds; return size + "," + arrayForTime + "," + arrayForeachTime + "," + listForTime + "," + listForeachTime + "\n"; } void OnGUI() { GUI.TextArea(new Rect(0, 0, Screen.width, Screen.height), report); } }
If you want to try out the test yourself, simply paste the above code into a TestScript.cs
file in your Unity project’s Assets
directory and attach it to the main camera game object in a new, empty project. Then build in non-development mode for 64-bit processors and run it windowed at 640×480 with fastest graphics. I ran it that way on this machine:
- 2.3 Ghz Intel Core i7-3615QM
- Mac OS X 10.10.4
- Unity 5.1.2f1, Mac OS X Standalone, x86_64, non-development
- 640×480, Fastest, Windowed
And here are the results I got:
Size | Array For Time | Array Foreach Time | List For Time | List Foreach Time |
---|---|---|---|---|
10 | 2 | 1 | 3 | 19 |
100 | 28 | 10 | 35 | 95 |
1000 | 243 | 75 | 343 | 832 |
The results for arrays are clearly in favor of foreach
as the faster loop by a margin of 2-3x. List
, on the other hand, favors the for
loop by 2-6x.
These are some really wide performance gaps that you should pay attention to if you are looping over some really long arrays or lists. However, keep in mind that the above loops were run 100,000 times so the actual times are much smaller. The worst time—a List
of 1,000 with foreach
—only took an average of 0.00832 milliseconds which is really small. A list of a million elements would presumably take 8 milliseconds and in that case you’d get a really nice optimization by switching to a for
loop. To do even better, consider an unsafe code loop.
In conclusion, there are two takeaways for this test. First, one of the types of loop is much faster than the other and it depends on what you’re looping over. Second, looping is so fast in both cases that the performance difference probably doesn’t matter in your app. If you’ve seen any evidence to the contrary or have any best practices you follow for your own looping, please share in the comments!
#1 by henke37 on August 3rd, 2015 ·
Is this a fair test? Iteration is not the same as a loop doing index lookups in sequence. Iteration should use an iterator so that linked lists go from O(n*n) to O(n).
#2 by jackson on August 3rd, 2015 ·
This is a fair test for the two collections involved: array and
List
. You’re right that it wouldn’t be a fair test had I included a linked list because thatfor
loop would be O(N2) due to constantly walking this list when a simple pointer/reference advancement could be used.List
, just as a reminder, is backed by an array whileLinkedList
is backed by a a chain of nodes (a.k.a. a linked list).For more on linked lists and why you shouldn’t use them anyhow, check out this article. But point taken- if you happen to be using one then you’ll probably get a huge speedup by using
foreach
.#3 by Brad on August 3rd, 2015 ·
As a Visual Studio console application (release build) with .NET 4.5.1, size = 1000:
Array For: 165
Array Foreach: 190
List For: 259
List Foreach: 438
#4 by jackson on August 3rd, 2015 ·
Thanks for the stats from a Microsoft .NET environment. That will surely be applicable to some use cases for C#, such as your console application. The article only showed results for Unity’s Mono environment so it’s good to get some more perspective. IL2CPP for iOS or HTML5 and performance on ARM processors may differ also, but I haven’t run those tests just due to time constraints. If you or anyone else happen to run them, please keep posting your results in the comments!
#5 by kzarczynski on August 4th, 2015 ·
To continue on the fairness of the test. Shouldn’t the foreach loop contain an assignment just as the for loop does?
As in:
And why not? ;)
#6 by jackson on August 4th, 2015 ·
I considered adding this assignment while writing the test, but then realized that the value from the collection (
List
, array) had already been read and assigned to a local variable:cur
. It seemed like assigningobj = cur
would make it less fair since there would be an extra assignment, similar to if thefor
test did this:#7 by kzarczynski on August 5th, 2015 ·
Yeah, that seemed to be the reason.
I’m really intrigued by the foreach&array performance. Another thing here would be to watch out for the memory allocation by foreach in the old Mono runtime that Unity uses – while this is not a big deal for PC games. I wonder, might that be the case that the array foreach is not allocating memory?
#8 by jackson on August 5th, 2015 ·
I just tried out that case. I put a
foreach
loop over an array in myUpdate()
and watched the Profiler pane in Unity to see how many “GC allocations per Frame” (under Memory) there were. Without the loop there were 8. With the loop there were still 8. I put in anew string('*',10)
just to make sure that value would go up and it indeed did rise.From that test I conclude that
foreach
on an array has been optimized to not really allocate anIEnumerator
. That’s good news because it means we can use the fastest loop without paying the price elsewhere in garbage collection.#9 by kzarczynski on August 17th, 2015 ·
I’ve decided to explore the topic a little bit further and you can read about it on my blog: http://blog.kzarczynski.com/2015/08/for-vs-foreach-follow-up/
#10 by gene on January 12th, 2016 ·
for (int i = 0, len = array.Length; i < len; ++i)
the array.length will be excuted for every loop …
#11 by jackson on January 12th, 2016 ·
No,
array.Length
is assigned to the loop-scopedlen
variable in the first part of thefor
loop that sets it up. It won’t be set every iteration any more thani
will. Onlyi < len
will be executed each iteration.#12 by Johnny Boy on May 19th, 2016 ·
While your comparisons are great, here’s a blog comparison that iterates over multiple kinds of objects, such as DataRows and custom objects, also including the performance of the While loop construct:
http://cc.davelozinski.com/c-sharp/for-vs-foreach-vs-while
At the minimum, it would be great to see your future articles incorporate the while loop too as a comparison.