When I started using C#, mainly because of XNA one of the things I got used to write is foreach loops instead of for, seemed easier and it’s a much cleaner code. Doing almost the same thing as a for loop I never really bother to see the differences, almost everyone in their XNA examples used it instead.
Today I decided to see the differences between them:
FOR
int[] values = new int[1]; int total = 0; for(int i = 0; i < values.Length; i++) { total += values[i]; } |
FOREACH
int[] values = new int[1]; int total = 0; foreach(int i in values ) { total += i; } |
In variable declaration, foreach has five variable declarations (three Int32 integers and two arrays of Int32) while for has only three (two Int32 integers and one Int32 array). When it goes to loop through, foreach copies the current array to a new one for the operation. While for doesn’t care of that part.
After the compiler interpretation to Assembly we get this:
FOR
cmp dword ptr [eax+4],0 i jle 0000000F mov ecx,dword ptr [eax+edx*4+8] inc edx cmp esi,dword ptr [eax+4] jl FFFFFFF8 |
FOREACH
cmp esi,dword ptr [ebx+4] i jl FFFFFFE3 cmp esi,dword ptr [ebx+4] jb 00000009 mov eax,dword ptr [ebx+esi*4+8] mov dword ptr [ebp-0Ch],eax mov eax,dword ptr [ebp-0Ch] add dword ptr [ebp-8],eax inc esi cmp esi,dword ptr [ebx+4] jl FFFFFFE3 |
As you can see we end up with much more instructions.
Some simple tests gives these results:
Using Objects | Using Integers | |||
FOR | FOREACH | FOR | FOREACH | |
ArrayList – 2147483 items | 88.6 | 115.9 | 65.1 | 134 |
generic collection – 2147483 items | 84.4 | 87.1 | 51.6 | 72.2 |
Array – 2147483 items | 48.1 | 49.8 | 17.5 | 21.7 |
*Time is in milliseconds.
So what I’ve done after this was to replace some heavy foreach code on my engine by for loops. I guess small things can be neglected but it’s always nice to know where bottlenecks may happen.
another “nice to know” article, Keep it up 🙂
hi,
First of all. Thanks very much for your useful post.
I just came across your blog and wanted to drop you a note telling you how impressed I was with the information you have posted here.
Please let me introduce you some info related to this post and I hope that it is useful for .Net community.
There is a good C# resource site, Have alook
http://www.csharptalk.com/2009/09/c-array.html
http://www.csharptalk.com/2009/10/creating-arrays.html
simi
There’s another caveat in something simple.
Take
i++;
and
++i;
The first one generates a second temporary integer that has the value of i+1, then assigns that temp value to i after the end of statement (‘;”). While the second one just ups i with one.
I think the .Net compiler/interpreter is smart enough most of the time to optimize a i++ to ++i (if possible). However since I know this I always use ++i in my for loops (and other code that just adds one).
I know this is an old post but it ranks fairly high on google so I am leaving this here for informational purposes.
Almost all the foreach s in my game engine code have led to errors at some point. Mostly due to the fact the in a foreach loop the collection cannot be modified. For this reason I use reversed for loops(counting backwards) almost exclusively. Not only do they not flinch at being modified, they also handle things gracefully when the current element is removed. This is because the only elements that have changed indexes are the ones that have already been processed.
First of all thanks for pointing it out. Nice research.
However the difference is not that important. ArrayList is totally deprecated today (replaced with fast generic collections). So the only somehow significant difference is in value types.
Additionally, what you should look at is not an assembly language, but the MSIL. It’s far more important, since we have different architectures. You might want to check compiler output of Mono as well.
I did also some testing and what I got is the following:
Iterating through array of ints:
[code]
[Test]
public unsafe void IsDenWpfRight()
{
const int ARRAY_SIZE = 1024*1024;
var array = new byte[ARRAY_SIZE];// 1MB = 256 pages
Random random = new Random();
random.NextBytes(array);
byte result = 0;
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i=0; i result = (byte)((result + i) % 251));
stopwatch.Stop();
Console.WriteLine(“Array.ForEach: ” + stopwatch.ElapsedTicks);
}
[/code]
Results:
for loop: 34426
foreach loop: 27932
Array.ForEach: 30604
For objects and collections:
[code]
private class SomeClass
{
public int field;
}
[Test]
public unsafe void IsDenWpfRight()
{
const int ARRAY_SIZE = 1024*1024;
var list = new List();
Random random = new Random();
for (int i=0 ; i< ARRAY_SIZE; i++)
{
list.Add(new SomeClass() {field = random.Next()});
}
int result = 0;
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i=0; i<ARRAY_SIZE; i++)
{
result = ((result + list[i].field)%513); // avoid compiler optimization for %256
}
stopwatch.Stop();
Console.WriteLine("for loop: " + stopwatch.ElapsedTicks);
stopwatch.Reset();
stopwatch.Start();
foreach (var i in list)
{
result = ((result + i.field) % 513); // avoid compiler optimization for %256
}
stopwatch.Stop();
Console.WriteLine("foreach loop: " + stopwatch.ElapsedTicks);
}
[/code]
Results:
for loop: 37629
foreach loop: 35891
From these tests I conclude that the performance of foreach is even better (maybe in some cases) or at least the same. So don't bother, write the style you like 🙂
Happy coding.