Foreach or For?

  • Thread starter Thread starter Phil
  • Start date Start date
P

Phil

Hi,

I read somewhere that the new version (v1.1) has improved the
performance of 'foreach' over 'for'. Is that true? I did some
measurements and I still think for has an upperhand... ?

Phil
 
Michael said:
I don't remember where I saw it, but I thought perhaps it was that
foreach was improved for arrays so it would act like a for loop. That
is, use simple indexing instead of MoveNext() and Current().

Even then I haven't been able to produce better results using foreach.
For out performs foreach in array accesses and array stores.


-Andre

I can't
 
There are a number of faults in your test program.. in the for loop,
you're using a constant for the range.. you should use ints.Length
instead as the JIT compiler optimizes it further (and easily). Secondly,
use the profiling API instead for accurate results.

Try the following two tests:

using System;

class Class1
{
[System.Runtime.InteropServices.DllImport ("Kernel32.dll")]
static extern bool QueryPerformanceCounter(ref long count);

[System.Runtime.InteropServices.DllImport ("Kernel32.dll")]
static extern bool QueryPerformanceFrequency(ref long count);

[STAThread]
static void Main(string[] args)
{
long count = 0;
long count1 = 0;
long freq = 0;
double result = 0;
int tmp = 0;

int[] arr = new int[1000];

QueryPerformanceFrequency(ref freq);
QueryPerformanceCounter(ref count);
for (int i=0; i<20000; i++) {
for(int j=0; j<n; j++)
{
tmp+=arr[j];
}
}
QueryPerformanceCounter(ref count1);

count = count1-count;
result = (double)(count)/(double)freq;

Console.WriteLine("Done in time(sec): {0}", result);
Console.ReadLine();
}
}

And:


using System;

class Class1
{
[System.Runtime.InteropServices.DllImport ("Kernel32.dll")]
static extern bool QueryPerformanceCounter(ref long count);

[System.Runtime.InteropServices.DllImport ("Kernel32.dll")]
static extern bool QueryPerformanceFrequency(ref long count);

[STAThread]
static void Main(string[] args)
{
long count = 0;
long count1 = 0;
long freq = 0;
double result = 0;
int tmp = 0;

int[] arr = new int[1000];

QueryPerformanceFrequency(ref freq);
QueryPerformanceCounter(ref count);
for (int i=0; i<20000; i++) {
foreach(int u in arr)
{
tmp+=u;
}
}
QueryPerformanceCounter(ref count1);

count = count1-count;
result = (double)(count)/(double)freq;

Console.WriteLine("Done in time(sec): {0}", result);
Console.ReadLine();
}
}


Justify this.

-Andre


Austin said:
I think you are noticing not the looping but the actual math being
done. Here's my code:

const ulong iterations=100000000;
DateTime dt;
uint[] ints={1,2,3,4,5,6,7,8,9,10};
uint len=10;
uint x=0;
ulong count=0;
dt=DateTime.Now;
ulong total=0;
while (count<iterations)
{
for (x=0;x<len;x++)
total+=ints[x];
count++;
}
TimeSpan ts1=DateTime.Now-dt;
count=0;
total=0;
dt=DateTime.Now;
while (count<iterations)
{
foreach (uint i in ints)
total+=i;
count++;
}
TimeSpan ts2=DateTime.Now-dt;

Console.WriteLine("For statement: {0} {1}ForEach statement: {2}",
ts1.ToString(), Environment.NewLine, ts2.ToString());
Console.ReadLine();

Austin Ehlers

Also, foreach incurs an array bounds check on every iteration.. I
suggest you change the count to 1000 and time again - you'll see a
noticeable difference. For me (i have a P4 2.4Ghz), a similar test
showed that For is atleast twice as fast as foreach.


-Andre
 
There is another problem.. don't test the two loops in the same program.
I think the JIT optimizes it further by realizing that the same array is
being accessed, and so it probably utilizes hardware registers
(enresigeration or whatever the word is) or it rearranges code in a way
that the second access would be faster (by making sure data is already
available in cache).. so the second time you access the loop using
foreach, you get better results. If you switch the two loops, I think it
will show the same for the 'For' loop (not sure though - haven't
tested)... but if you try it out separately, you see a noticeable
difference.


-Andre
There are a number of faults in your test program.. in the for loop,
you're using a constant for the range.. you should use ints.Length
instead as the JIT compiler optimizes it further (and easily). Secondly,
use the profiling API instead for accurate results.

Try the following two tests:

using System;

class Class1
{
[System.Runtime.InteropServices.DllImport ("Kernel32.dll")]
static extern bool QueryPerformanceCounter(ref long count);

[System.Runtime.InteropServices.DllImport ("Kernel32.dll")]
static extern bool QueryPerformanceFrequency(ref long count);

[STAThread]
static void Main(string[] args)
{
long count = 0;
long count1 = 0;
long freq = 0;
double result = 0;
int tmp = 0;

int[] arr = new int[1000];

QueryPerformanceFrequency(ref freq);
QueryPerformanceCounter(ref count);
for (int i=0; i<20000; i++) {
for(int j=0; j<n; j++)
{
tmp+=arr[j];
}
}
QueryPerformanceCounter(ref count1);

count = count1-count;
result = (double)(count)/(double)freq;

Console.WriteLine("Done in time(sec): {0}", result);
Console.ReadLine();
}
}

And:


using System;

class Class1
{
[System.Runtime.InteropServices.DllImport ("Kernel32.dll")]
static extern bool QueryPerformanceCounter(ref long count);

[System.Runtime.InteropServices.DllImport ("Kernel32.dll")]
static extern bool QueryPerformanceFrequency(ref long count);

[STAThread]
static void Main(string[] args)
{
long count = 0;
long count1 = 0;
long freq = 0;
double result = 0;
int tmp = 0;

int[] arr = new int[1000];

QueryPerformanceFrequency(ref freq);
QueryPerformanceCounter(ref count);
for (int i=0; i<20000; i++) {
foreach(int u in arr)
{
tmp+=u;
}
}
QueryPerformanceCounter(ref count1);

count = count1-count;
result = (double)(count)/(double)freq;

Console.WriteLine("Done in time(sec): {0}", result);
Console.ReadLine();
}
}


Justify this.

-Andre


Austin said:
I think you are noticing not the looping but the actual math being
done. Here's my code:

const ulong iterations=100000000;
DateTime dt;
uint[] ints={1,2,3,4,5,6,7,8,9,10};
uint len=10;
uint x=0;
ulong count=0;
dt=DateTime.Now;
ulong total=0;
while (count<iterations)
{
for (x=0;x<len;x++)
total+=ints[x];
count++;
}
TimeSpan ts1=DateTime.Now-dt;
count=0;
total=0;
dt=DateTime.Now;
while (count<iterations)
{
foreach (uint i in ints)
total+=i;
count++;
}
TimeSpan ts2=DateTime.Now-dt;

Console.WriteLine("For statement: {0} {1}ForEach statement: {2}",
ts1.ToString(), Environment.NewLine, ts2.ToString());
Console.ReadLine();

Austin Ehlers

Also, foreach incurs an array bounds check on every iteration.. I
suggest you change the count to 1000 and time again - you'll see a
noticeable difference. For me (i have a P4 2.4Ghz), a similar test
showed that For is atleast twice as fast as foreach.


-Andre

Austin Ehlers wrote:




Hi,

I read somewhere that the new version (v1.1) has improved the
performance of 'foreach' over 'for'. Is that true? I did some
measurements and I still think for has an upperhand... ?

Phil


I did a simple test. I cycled through an array of integers
{1,2,3,4,5,6,7,8,9,10} and added them to a total counter.
I did this 100 million times. On an Athlon XP 2400+, here are the
times:

for statement: 00:00:08.1093750
foreach statement: 00:00:08.1406250

As you can see, 4 hundredths of a second for 100 million times in
neglible. So, I'd say that in all but the most performance intensive
apps, foreach is equal to for in speed. (Don't forget, foreach is
readonly)

Austin Ehlers
 
Using your code, compiled with as "csc for.cs" and "csc foreach.cs",
I get:

C:\>for.exe
Done in time(sec): 0.0318314199151009

C:\>foreach
Done in time(sec): 0.0212663900020813

I changed the j<n to j<arr.Length

Austin Ehlers

There are a number of faults in your test program.. in the for loop,
you're using a constant for the range.. you should use ints.Length
instead as the JIT compiler optimizes it further (and easily). Secondly,
use the profiling API instead for accurate results.

Try the following two tests:

using System;

class Class1
{
[System.Runtime.InteropServices.DllImport ("Kernel32.dll")]
static extern bool QueryPerformanceCounter(ref long count);

[System.Runtime.InteropServices.DllImport ("Kernel32.dll")]
static extern bool QueryPerformanceFrequency(ref long count);

[STAThread]
static void Main(string[] args)
{
long count = 0;
long count1 = 0;
long freq = 0;
double result = 0;
int tmp = 0;

int[] arr = new int[1000];

QueryPerformanceFrequency(ref freq);
QueryPerformanceCounter(ref count);
for (int i=0; i<20000; i++) {
for(int j=0; j<n; j++)
{
tmp+=arr[j];
}
}
QueryPerformanceCounter(ref count1);

count = count1-count;
result = (double)(count)/(double)freq;

Console.WriteLine("Done in time(sec): {0}", result);
Console.ReadLine();
}
}

And:


using System;

class Class1
{
[System.Runtime.InteropServices.DllImport ("Kernel32.dll")]
static extern bool QueryPerformanceCounter(ref long count);

[System.Runtime.InteropServices.DllImport ("Kernel32.dll")]
static extern bool QueryPerformanceFrequency(ref long count);

[STAThread]
static void Main(string[] args)
{
long count = 0;
long count1 = 0;
long freq = 0;
double result = 0;
int tmp = 0;

int[] arr = new int[1000];

QueryPerformanceFrequency(ref freq);
QueryPerformanceCounter(ref count);
for (int i=0; i<20000; i++) {
foreach(int u in arr)
{
tmp+=u;
}
}
QueryPerformanceCounter(ref count1);

count = count1-count;
result = (double)(count)/(double)freq;

Console.WriteLine("Done in time(sec): {0}", result);
Console.ReadLine();
}
}


Justify this.

-Andre


Austin said:
I think you are noticing not the looping but the actual math being
done. Here's my code:

const ulong iterations=100000000;
DateTime dt;
uint[] ints={1,2,3,4,5,6,7,8,9,10};
uint len=10;
uint x=0;
ulong count=0;
dt=DateTime.Now;
ulong total=0;
while (count<iterations)
{
for (x=0;x<len;x++)
total+=ints[x];
count++;
}
TimeSpan ts1=DateTime.Now-dt;
count=0;
total=0;
dt=DateTime.Now;
while (count<iterations)
{
foreach (uint i in ints)
total+=i;
count++;
}
TimeSpan ts2=DateTime.Now-dt;

Console.WriteLine("For statement: {0} {1}ForEach statement: {2}",
ts1.ToString(), Environment.NewLine, ts2.ToString());
Console.ReadLine();

Austin Ehlers

Also, foreach incurs an array bounds check on every iteration.. I
suggest you change the count to 1000 and time again - you'll see a
noticeable difference. For me (i have a P4 2.4Ghz), a similar test
showed that For is atleast twice as fast as foreach.


-Andre

Austin Ehlers wrote:




Hi,

I read somewhere that the new version (v1.1) has improved the
performance of 'foreach' over 'for'. Is that true? I did some
measurements and I still think for has an upperhand... ?

Phil

I did a simple test. I cycled through an array of integers
{1,2,3,4,5,6,7,8,9,10} and added them to a total counter.
I did this 100 million times. On an Athlon XP 2400+, here are the
times:

for statement: 00:00:08.1093750
foreach statement: 00:00:08.1406250

As you can see, 4 hundredths of a second for 100 million times in
neglible. So, I'd say that in all but the most performance intensive
apps, foreach is equal to for in speed. (Don't forget, foreach is
readonly)

Austin Ehlers
 
What machine do you have?

-Andre

Austin said:
Using your code, compiled with as "csc for.cs" and "csc foreach.cs",
I get:

C:\>for.exe
Done in time(sec): 0.0318314199151009

C:\>foreach
Done in time(sec): 0.0212663900020813

I changed the j<n to j<arr.Length

Austin Ehlers

There are a number of faults in your test program.. in the for loop,
you're using a constant for the range.. you should use ints.Length
instead as the JIT compiler optimizes it further (and easily). Secondly,
use the profiling API instead for accurate results.

Try the following two tests:

using System;

class Class1
{
[System.Runtime.InteropServices.DllImport ("Kernel32.dll")]
static extern bool QueryPerformanceCounter(ref long count);

[System.Runtime.InteropServices.DllImport ("Kernel32.dll")]
static extern bool QueryPerformanceFrequency(ref long count);

[STAThread]
static void Main(string[] args)
{
long count = 0;
long count1 = 0;
long freq = 0;
double result = 0;
int tmp = 0;

int[] arr = new int[1000];

QueryPerformanceFrequency(ref freq);
QueryPerformanceCounter(ref count);
for (int i=0; i<20000; i++) {
for(int j=0; j<n; j++)
{
tmp+=arr[j];
}
}
QueryPerformanceCounter(ref count1);

count = count1-count;
result = (double)(count)/(double)freq;

Console.WriteLine("Done in time(sec): {0}", result);
Console.ReadLine();
}
}

And:


using System;

class Class1
{
[System.Runtime.InteropServices.DllImport ("Kernel32.dll")]
static extern bool QueryPerformanceCounter(ref long count);

[System.Runtime.InteropServices.DllImport ("Kernel32.dll")]
static extern bool QueryPerformanceFrequency(ref long count);

[STAThread]
static void Main(string[] args)
{
long count = 0;
long count1 = 0;
long freq = 0;
double result = 0;
int tmp = 0;

int[] arr = new int[1000];

QueryPerformanceFrequency(ref freq);
QueryPerformanceCounter(ref count);
for (int i=0; i<20000; i++) {
foreach(int u in arr)
{
tmp+=u;
}
}
QueryPerformanceCounter(ref count1);

count = count1-count;
result = (double)(count)/(double)freq;

Console.WriteLine("Done in time(sec): {0}", result);
Console.ReadLine();
}
}


Justify this.

-Andre


Austin said:
I think you are noticing not the looping but the actual math being
done. Here's my code:

const ulong iterations=100000000;
DateTime dt;
uint[] ints={1,2,3,4,5,6,7,8,9,10};
uint len=10;
uint x=0;
ulong count=0;
dt=DateTime.Now;
ulong total=0;
while (count<iterations)
{
for (x=0;x<len;x++)
total+=ints[x];
count++;
}
TimeSpan ts1=DateTime.Now-dt;
count=0;
total=0;
dt=DateTime.Now;
while (count<iterations)
{
foreach (uint i in ints)
total+=i;
count++;
}
TimeSpan ts2=DateTime.Now-dt;

Console.WriteLine("For statement: {0} {1}ForEach statement: {2}",
ts1.ToString(), Environment.NewLine, ts2.ToString());
Console.ReadLine();

Austin Ehlers

Also, foreach incurs an array bounds check on every iteration.. I
suggest you change the count to 1000 and time again - you'll see a
noticeable difference. For me (i have a P4 2.4Ghz), a similar test
showed that For is atleast twice as fast as foreach.


-Andre

Austin Ehlers wrote:






Hi,

I read somewhere that the new version (v1.1) has improved the
performance of 'foreach' over 'for'. Is that true? I did some
measurements and I still think for has an upperhand... ?

Phil

I did a simple test. I cycled through an array of integers
{1,2,3,4,5,6,7,8,9,10} and added them to a total counter.
I did this 100 million times. On an Athlon XP 2400+, here are the
times:

for statement: 00:00:08.1093750
foreach statement: 00:00:08.1406250

As you can see, 4 hundredths of a second for 100 million times in
neglible. So, I'd say that in all but the most performance intensive
apps, foreach is equal to for in speed. (Don't forget, foreach is
readonly)

Austin Ehlers
 
I have a Pentium 4 2.4 Ghz, 256 MB RAM, .NET V1.1 here's what I get:

For loop:
Done in time(sec): 0.0169739450125644


Foreach loop:
Done in time(sec): 0.020767443906977


Can it be something to do with the hardware then?! I have no other
explanation.

-Andre
 
A couple of things. First, if you are sure of your array access code, you
can shut off bounds checking on each indexer access by marking the code as
unsafe. You can then obtain a pointer to the first element then move the
pointer since arrays are stored in contiguous memory space. This only works
for primitive types.

Also, as an FYI, you won't be able to change any values using the foreach
syntax since under the hood this loads up an enumerator with a copy of the
array.

Andre said:
There are a number of faults in your test program.. in the for loop,
you're using a constant for the range.. you should use ints.Length
instead as the JIT compiler optimizes it further (and easily). Secondly,
use the profiling API instead for accurate results.

Try the following two tests:

using System;

class Class1
{
[System.Runtime.InteropServices.DllImport ("Kernel32.dll")]
static extern bool QueryPerformanceCounter(ref long count);

[System.Runtime.InteropServices.DllImport ("Kernel32.dll")]
static extern bool QueryPerformanceFrequency(ref long count);

[STAThread]
static void Main(string[] args)
{
long count = 0;
long count1 = 0;
long freq = 0;
double result = 0;
int tmp = 0;

int[] arr = new int[1000];

QueryPerformanceFrequency(ref freq);
QueryPerformanceCounter(ref count);
for (int i=0; i<20000; i++) {
for(int j=0; j<n; j++)
{
tmp+=arr[j];
}
}
QueryPerformanceCounter(ref count1);

count = count1-count;
result = (double)(count)/(double)freq;

Console.WriteLine("Done in time(sec): {0}", result);
Console.ReadLine();
}
}

And:


using System;

class Class1
{
[System.Runtime.InteropServices.DllImport ("Kernel32.dll")]
static extern bool QueryPerformanceCounter(ref long count);

[System.Runtime.InteropServices.DllImport ("Kernel32.dll")]
static extern bool QueryPerformanceFrequency(ref long count);

[STAThread]
static void Main(string[] args)
{
long count = 0;
long count1 = 0;
long freq = 0;
double result = 0;
int tmp = 0;

int[] arr = new int[1000];

QueryPerformanceFrequency(ref freq);
QueryPerformanceCounter(ref count);
for (int i=0; i<20000; i++) {
foreach(int u in arr)
{
tmp+=u;
}
}
QueryPerformanceCounter(ref count1);

count = count1-count;
result = (double)(count)/(double)freq;

Console.WriteLine("Done in time(sec): {0}", result);
Console.ReadLine();
}
}


Justify this.

-Andre


Austin said:
I think you are noticing not the looping but the actual math being
done. Here's my code:

const ulong iterations=100000000;
DateTime dt;
uint[] ints={1,2,3,4,5,6,7,8,9,10};
uint len=10;
uint x=0;
ulong count=0;
dt=DateTime.Now;
ulong total=0;
while (count<iterations)
{
for (x=0;x<len;x++)
total+=ints[x];
count++;
}
TimeSpan ts1=DateTime.Now-dt;
count=0;
total=0;
dt=DateTime.Now;
while (count<iterations)
{
foreach (uint i in ints)
total+=i;
count++;
}
TimeSpan ts2=DateTime.Now-dt;

Console.WriteLine("For statement: {0} {1}ForEach statement: {2}",
ts1.ToString(), Environment.NewLine, ts2.ToString());
Console.ReadLine();

Austin Ehlers

Also, foreach incurs an array bounds check on every iteration.. I
suggest you change the count to 1000 and time again - you'll see a
noticeable difference. For me (i have a P4 2.4Ghz), a similar test
showed that For is atleast twice as fast as foreach.


-Andre

Austin Ehlers wrote:




Hi,

I read somewhere that the new version (v1.1) has improved the
performance of 'foreach' over 'for'. Is that true? I did some
measurements and I still think for has an upperhand... ?

Phil

I did a simple test. I cycled through an array of integers
{1,2,3,4,5,6,7,8,9,10} and added them to a total counter.
I did this 100 million times. On an Athlon XP 2400+, here are the
times:

for statement: 00:00:08.1093750
foreach statement: 00:00:08.1406250

As you can see, 4 hundredths of a second for 100 million times in
neglible. So, I'd say that in all but the most performance intensive
apps, foreach is equal to for in speed. (Don't forget, foreach is
readonly)

Austin Ehlers
 
Back
Top