Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

for vs foreach

2 views
Skip to first unread message

Max

unread,
Nov 8, 2002, 5:31:17 PM11/8/02
to
which is the efficient way (or has better performance)? for or foreach?

in case where we can use either of them.

Thanks.


Mickey Williams

unread,
Nov 8, 2002, 5:54:27 PM11/8/02
to
"Max" <vmek...@hotmail.com> wrote in message
news:OU2JIZ3hCHA.456@tkmsftngp12...

> which is the efficient way (or has better performance)? for or foreach?
>
> in case where we can use either of them.

In the case of arrays, the compiler emits code that's special-cased to be as
efficient as a for-loop - you can see this for yourself if you ILDASM a
foreach statement over an array and compare it to a for-loop. In other
non-array cases, the code emitted for a foreach loop extracts the enumerator
and uses the enumerator's methods to walk the collection. Whether this is
more efficient than using the indexer exposed by the collection really
depends to a large degree on the implementation. More code is generated on
the client for the enumerator used by the foreach statement, but it's
possible for a well-written enumerator to take advantage of internal
knowledge of the container's implementation, especially for more complex
data structures. Having said that, it's my feeling that in most
non-degenerate cases the foreach statement should be slightly slower - but
the cost is going to be very light.

--
Mickey Williams
Author, "Microsoft Visual C# .NET", Microsoft Press


Gregor Noriskin [MS]

unread,
Nov 8, 2002, 7:48:43 PM11/8/02
to
If you are doing significant work through each iteration of the loop the
relative cost of "for" versus "foreach" should not be significant, but
"foreach" is generally slower and has a greater working set impact than
"for". As a genaral rule, when in doubt you should use "for" in performance
sensitive code paths. Also if you are iterating over an array using "for"
you should use the following pattern:

for(int i=0;i<myArray.Length;i++)
{
myArray[i] = ...
}

The C# compiler will detect this pattern, i.e. explicit test in "for"
statement for array length, and hoist the range check. If you are doing a
small amount of work through each iterations, and you are doing a lot of
iterations, this will improve the performance of the loop.

Gregor Noriskin
CLR Performance PM
Microsoft

"Mickey Williams" <m...@codevtech.com> wrote in message
news:ecN#Xn3hCHA.2340@tkmsftngp08...

Eric Gunnerson [MS]

unread,
Nov 8, 2002, 8:12:12 PM11/8/02
to
I would suggest that you use foreach wherever possible when you write your
code. If profiling shows that you have a hot-spot in a method that uses
foreach, you can then consider using a for loop instead.

Otherwise, I think you are likely to write the more complex and
tougher-to-maintain for loop where you don't need to.

--
Visit the C# product team at http://www.gotdotnet.com/team/csharp

This posting is provided "AS IS" with no warranties, and confers no rights.

"Max" <vmek...@hotmail.com> wrote in message
news:OU2JIZ3hCHA.456@tkmsftngp12...

Ted Howard

unread,
Nov 8, 2002, 8:33:29 PM11/8/02
to
"As a genaral rule, when in doubt you should use "for" in performance
sensitive code paths."

Really? I would have thought that 'for' would be better with arrays and
'foreach' better for other containers. My thoughts are based on the STL and
iterators. In particular, a forward-only iterator could be optimized nicely.
Also, I would have thought that a 'foreach' could be optimized more easily
by the compiler. Oh well, I would've figured it out if the Profiler
complained.

-Ted

"Gregor Noriskin [MS]" <gre...@online.microsoft.com> wrote in message
news:OOXwOm4hCHA.1356@tkmsftngp11...

Chad Myers

unread,
Nov 8, 2002, 9:33:10 PM11/8/02
to
for is quicker than foreach.

However, for large collections, the indexer can actually
significantlly impact performance of the loop. This can
be improved by using an iterator.

For a large collection the performance impact of the
foreach is negated and then some (a lot of some) by the
speed of using the enumerator vs the indexer.

-c

"Ted Howard" <ted(underscore)yantis@ no spam yahoo.com> wrote in message
news:OW7zO$4hCHA.2560@tkmsftngp12...

Chris R

unread,
Nov 9, 2002, 11:03:42 AM11/9/02
to
Adding 2,000,000 values to a collection. All times are
approximates, based on several runs, with the first run discarded as
JITter compilation.
---------------------------------------------
speed (seconds) for value types (ints)
Retrieving
Adding With for With foreach
ArrayList 1.80 0.21 0.32
DynamicArray 0.22 0.13 0.20
Static size array 0.04 0.05 0.055
---------------------------------------------
speed (seconds) for reference types (strings)
Retrieving
Adding With for With foreach
ArrayList 0.37 0.13 0.22
DynamicArray 0.34 0.13 0.20
Static size array 0.06 0.05 0.055
---------------------------------------------
First thing to note is that it took a 2,000,000 length array to get
a significant value to work with. Few applications will need this kind
of tweaking.

DynamicArray: This is a set of classes that I wrote myself to
immitate ArrayList, but with strong typing. I didn't use the built in
collection classes, but built from scratch. It dynamically resizes
itself when the count exceeds the capacity of the array. I built these
classes in response to a question about how would use of Generics be
better than using collection classes. A Generic ArrayList should have
the same speed as my DynamicArray classes.

As for the static arrays, who wants to keep that large of an array
around, if the size is dynamic and may hold 2000 values, rather than
2000000. I remember having seen old C language programs where a large
number of large static-sized arrays slowed down a program, due to hard
disk swapping.

Also note that using a DynamicArray or ArrayList for a reference
type are nearly identical. It is when using a DynamicArray versus an
ArrayList for the value types that you see a significant variance.

Chris R.
Disclaimer: The above information is for experimental & conceptual
work only and should not be considered implications for which pattern is
better to use.
The string added was a constant string of 8 characters, so they all
pointed to the same thing. For the integers, IntArray[i] = i;


"Ted Howard" <ted(underscore)yantis@ no spam yahoo.com> wrote in message
news:OW7zO$4hCHA.2560@tkmsftngp12...

Mickey Williams

unread,
Nov 11, 2002, 1:01:29 PM11/11/02
to
> Also if you are iterating over an array using "for"
> you should use the following pattern:
>
> for(int i=0;i<myArray.Length;i++)
> {
> myArray[i] = ...
> }
>
> The C# compiler will detect this pattern, i.e. explicit test in "for"
> statement for array length, and hoist the range check.

This work might be done by the JIT'er, but it's definitely not done by the
C# compiler. Here's the C#:

static void printWithFor(int [] rg)
{
for(int i = 0; i < rg.Length; ++i)
{
Console.WriteLine(rg[i]);
}
}

And here's the IL in release build:

.method private hidebysig static void printWithFor(int32[] rg) cil managed
{
// Code size 23 (0x17)
.maxstack 2
.locals init (int32 V_0)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: br.s IL_0010
IL_0004: ldarg.0
IL_0005: ldloc.0
IL_0006: ldelem.i4
IL_0007: call void [mscorlib]System.Console::WriteLine(int32)
IL_000c: ldloc.0
IL_000d: ldc.i4.1
IL_000e: add
IL_000f: stloc.0
IL_0010: ldloc.0
IL_0011: ldarg.0
IL_0012: ldlen
IL_0013: conv.i4
IL_0014: blt.s IL_0004
IL_0016: ret
} // end of method Class1::printWithFor

Offsets 0c - 14 test the counter (stack location 0) with the length of the
array, and branch to the top of the loop when the array hasn't been fully
consumed. If the test were hoisted, I would expect to see lines 11-13
replaced with a test of a local variable that was created before entering
the loop. Perhaps the cost of checking the array length with ldlen is so
small that there's no point in attempting to optimize away the call?

Anyhow, compare this to an equivalent foreach, here:
static void printWithForeach(int [] rg)
{
foreach(int n in rg)
{
Console.WriteLine(n);
}
}

And its IL here:
.method private hidebysig static void printWithForeach(int32[] rg) cil
managed
{
// Code size 27 (0x1b)
.maxstack 2
.locals init (int32 V_0,
int32[] V_1,
int32 V_2)
IL_0000: ldarg.0
IL_0001: stloc.1
IL_0002: ldc.i4.0
IL_0003: stloc.2
IL_0004: br.s IL_0014
IL_0006: ldloc.1
IL_0007: ldloc.2
IL_0008: ldelem.i4
IL_0009: stloc.0
IL_000a: ldloc.0
IL_000b: call void [mscorlib]System.Console::WriteLine(int32)
IL_0010: ldloc.2
IL_0011: ldc.i4.1
IL_0012: add
IL_0013: stloc.2
IL_0014: ldloc.2
IL_0015: ldloc.1
IL_0016: ldlen
IL_0017: conv.i4
IL_0018: blt.s IL_0006
IL_001a: ret
} // end of method Class1::printWithForeach

The difference between a trivial array iteration with for vs. foreach is 4
bytes of IL and two temporary local vars (one is used to for the temporary
cursor value, but why does the foreach loop copy a reference to the
array? ) - As Eric pointed out, the C# code is much clearer, and I'm happy
to pay four bytes of IL for much clearer code in most cases - the cost
difference for all but trivial work is completely insignificant.

Chad Myers

unread,
Nov 11, 2002, 3:50:04 PM11/11/02
to
Do you have evidence to back this up?

I recall doing some tests and for() was always faster for array lists,
but foreach() was faster for collections/enumerators.

However, less than around 2,000,000 objects showed almost no difference
among any of the various combinations.

-c

"Rob Epstein" <rob_e...@hotmail.com> wrote in message
news:OkPlwJciCHA.1336@tkmsftngp11...
> With arrays larger than ~35,000 items, a for loop outperforms foreach.
> Anything less than that and the foreach statement is more performant.
>
> --
> Hope that helps,
> Rob Epstein
> Sr. Application Architect
> ComputerJobs.com
> http://www.computerjobs.com
> "Nothing's impossible until proven so."


>
>
> "Mickey Williams" <m...@codevtech.com> wrote in message

> news:OaxGtxaiCHA.2364@tkmsftngp08...

Mickey Williams

unread,
Nov 11, 2002, 4:19:06 PM11/11/02
to
> With arrays larger than ~35,000 items, a for loop outperforms foreach.
> Anything less than that and the foreach statement is more performant.

For an array, the foreach statement should not be more performant - the code
path is (very slightly) longer, and there are extra local variables. There's
more stuff in the sandwich, so it (should) take longer to eat it. However,
the cost difference between the two options should always be so small as to
be almost undetectable unless you have large numbers of elements and you're
doing computationally trivial work. Iterating over 35,000 (or 2,000,000
items elsewhere in the thread) is not the general case in my opinion, but if
you're doing that kind of work and you're sensitive to even the smallest
perf costs, then maybe the perf advantages of a for loop exceed the improved
readability of a foreach loop.

Having said that - for other types of containers that are potentially more
complex you can't make the assumption that an indexer is faster than an
enumerator without profiling, or unless you have some knowledge of the
implementation. If the container is based on an underlying array, as are the
Microsoft collection types, an indexer may be faster than the indirection
required for an enumerator. If the container has more complex internals, it
may be faster to use an enumerator.

An analysis of the cost of iterating over an array or ArrayList can't be
extended to all types of maps, trees and tables. Consider an nway tree built
with individual (non-aray) nodes - how do you immediately access the nth
(say 34,323rd) element without traversal, and without a parallel data
structure? An enumerator will beat an indexer in this case. In my opinion,
you should write clean code first, then profile to look for hotspots.
Frankly, when I profile my apps, the perf wins are never found changing
foreach loops into for loops.

Rob Epstein

unread,
Nov 11, 2002, 3:40:38 PM11/11/02
to
With arrays larger than ~35,000 items, a for loop outperforms foreach.
Anything less than that and the foreach statement is more performant.

--


Hope that helps,
Rob Epstein
Sr. Application Architect
ComputerJobs.com
http://www.computerjobs.com
"Nothing's impossible until proven so."

"Mickey Williams" <m...@codevtech.com> wrote in message

news:OaxGtxaiCHA.2364@tkmsftngp08...

Robert Paveza

unread,
Nov 12, 2002, 3:51:03 AM11/12/02
to
Without looking at performance issues....

Take a look at the one MAJOR, HUGE advantage to a for over a foreach:

you can index multiple arrays!

Personally, I prefer foreach - and as the last guy said, for vs foreach
will cause a very insignificant slowdown (0.05 to 0.055 seconds for
2,000,000 iterations was shown above!). However, you can't do something
like this:

int[] iar = new int[2000000];
short[] sar = new short[2000000];
// initialize the array values
// ...
foreach (int i in iar) {
i = Convert.ToInt32(sar[]); //huh? how do I access sar's members?
}

This is a case where for would be appropriate.

for (int c = 0; c < 2000000; c++) {
iar[c] = Convert.ToInt32(sar[c]);
}

Sometimes people just need to be told these things. They aren't always
apparent - I remember having issues like that when I was first starting
too!

============
Robert A. Paveza
rob...@paveza.net

*** Sent via Developersdex http://www.developersdex.com ***
Don't just participate in USENET...get rewarded for it!

per larsen

unread,
Nov 12, 2002, 5:11:39 AM11/12/02
to
For completeness, here's the actual code generated on my system
(W2K/Pentium III/CLR1.0) for the two versions.

First, the for(...) version:

push edi
push esi
mov esi, ecx
[form1.cs.679] for(int i = 0; i < rg.Length; ++i)
xor edi, edi
[form1.cs.679] for(int i = 0; i < rg.Length; ++i)
cmp dword ptr [esi+04h], 00h
jle @@2
[form1.cs.681] Console.WriteLine(rg[i]);
@@1:
cmp edi, [esi+04h]
jnb @@3
mov edx, [esi+edi*4+08h]
mov ecx, [025E0FECh]
mov eax, [ecx]
call [eax+0BCh]
[form1.cs.679] for(int i = 0; i < rg.Length; ++i)
inc edi
[form1.cs.679] for(int i = 0; i < rg.Length; ++i)
cmp edi, [esi+04h]
jl @@1
[form1.cs.683] }
@@2:
pop esi
pop edi
ret
@@3:
xor ecx, ecx
call 074723E3Fh
int3

Then, the foreach(...) version:

push edi
push esi
[form1.cs.687] foreach(int n in rg)
mov edi, ecx
[form1.cs.687] foreach(int n in rg)
xor esi, esi
cmp dword ptr [edi+04h], 00h
jle @@2
@@1:
cmp esi, [edi+04h]
jnb @@3
mov edx, [edi+esi*4+08h]
[form1.cs.689] Console.WriteLine(n);
mov ecx, [025E0FECh]
mov eax, [ecx]
call [eax+0BCh]
[form1.cs.687] foreach(int n in rg)
inc esi
cmp esi, [edi+04h]
jl @@1
[form1.cs.691] }
@@2:
pop esi
pop edi
ret
@@3:
xor ecx, ecx
call 074723B37h
int3

As you can see, the code is identical, except for the registers used.

- Per


Chad Myers

unread,
Nov 12, 2002, 11:50:35 AM11/12/02
to
Use for for arrays, use foreach() for collections.

It's pretty much that simple.

-c

"Robert Paveza" <rob...@paveza.net> wrote in message
news:OktYiiiiCHA.1336@tkmsftngp11...

0 new messages