 |
|
 |
While reading all the conflicting reports, I wrote my own little sample, posted below. Here are the results:
Object Test Results
FOR loop time on ArrayList with 2147483 items looped 10 times: Average Elapsed Milliseconds: 88.6
FOREACH loop time on ArrayList with 2147483 items looped 10 times: Average Elapsed Milliseconds: 115.9
FOR loop time on generic collection with 2147483 items looped 10 times: Average Elapsed Milliseconds: 84.4
FOREACH loop time on generic collection with 2147483 items looped 10 times: Average Elapsed Milliseconds: 87.1
FOR loop time on array with 2147483 items looped 10 times: Average Elapsed Milliseconds: 48.1
FOREACH loop time on array with 2147483 items looped 10 times: Average Elapsed Milliseconds: 49.8
Int Test Results
FOR loop time on ArrayList with 2147483 items looped 10 times: Average Elapsed Milliseconds: 65.1
FOREACH loop time on ArrayList with 2147483 items looped 10 times: Average Elapsed Milliseconds: 134
FOR loop time on generic collection with 2147483 items looped 10 times: Average Elapsed Milliseconds: 51.6
FOREACH loop time on generic collection with 2147483 items looped 10 times: Average Elapsed Milliseconds: 72.2
FOR loop time on array with 2147483 items looped 10 times: Average Elapsed Milliseconds: 17.5
FOREACH loop time on array with 2147483 items looped 10 times: Average Elapsed Milliseconds: 21.7
This tests ArrayLists, Generic collections, and arrays holding the same type of information with the same lengths. The for/foreach loops do nothing more then set a number. Personally I wish the results were the opposite as foreach is less to type then for (int i = i < ? ; i++)
You can run this sample and it will loop millions and millions of objects/ints and average them to produce a viable result. I ran it about 10 times now illiterating through over 100 million items with the same results each time.
By default the sample will pause 5 seconds in between runs. You can optionally output the results to a file as well. If you find any issues please post them. FYI this sample was ran on a 1.6ghz x 2 Vista laptop with 2gb of ram if you want to compare results.
using System; using System.Collections.Generic; using System.Text; using System.Diagnostics; using System.Collections; using System.Threading; using System.IO;
namespace FOREACHVSFOR { class Program { #region Array/Collection static ArrayList ari1 = null; static ArrayList ari2 = null; static List<int> ari3 = null; static List<int> ari4 = null; static int[] ari5 = null; static int[] ari6 = null;
static ArrayList arl1 = null; static ArrayList arl2 = null; static List<BoringObjectClass> arl3 = null; static List<BoringObjectClass> arl4 = null; static BoringObjectClass[] arl5 = null; static BoringObjectClass[] arl6 = null; #endregion
#region Times static long ar1Time = 0; static long ar2Time = 0; static long ar3Time = 0; static long ar4Time = 0; static long ar5Time = 0; static long ar6Time = 0; #endregion
class BoringObjectClass: Object { public int SomeInt = 0; public BoringObjectClass(int v) { SomeInt=v; } } static int intsToTest = 0;
static int objectsToTest = 0;
static bool SaveToLog = true;
static string LogFileName = "FORVSFOREACH.log";
static bool AppendLog = false;
static int SleepTimeInBetween = 5000;
static StringBuilder builder;
static char[] sp = new char[] { char.Parse("\n") };
static void IntCheck() { Stopwatch sp = new Stopwatch(); int fill = 0;
if (ari1 == null || ari1.Count != intsToTest) { ari1 = null; ari1 = new ArrayList(intsToTest); } if (ari2 == null || ari2.Count != intsToTest) { ari2 = null; ari2 = new ArrayList(intsToTest); } if (ari3 == null || ari3.Count != intsToTest) { ari3 = null; ari3 = new List<int>(intsToTest); } if (ari4 == null || ari4.Count != intsToTest) { ari4 = null; ari4 = new List<int>(intsToTest); } if (ari5 == null || ari5.Length != intsToTest) { ari5 = null; ari5 = new int[intsToTest]; } if (ari6 == null || ari6.Length != intsToTest) { ari6 = null; ari6 = new int[intsToTest]; }
while (fill < intsToTest) { ari1.Add(fill); ari2.Add(fill); ari3.Add(fill); ari4.Add(fill); ari5[fill] = fill; ari6[fill] = fill;
fill++; }
fill = 0; sp.Reset(); Thread.Sleep(SleepTimeInBetween); sp.Start(); for (int i = 0; i < ari1.Count; i++) fill = (int) ari1[i]; sp.Stop(); ar1Time += sp.ElapsedMilliseconds;
fill = 0; sp.Reset(); Thread.Sleep(SleepTimeInBetween); sp.Start(); foreach (int i in ari2) fill = (int) ari2[i]; sp.Stop(); ar2Time+= sp.ElapsedMilliseconds;
fill = 0; sp.Reset(); Thread.Sleep(SleepTimeInBetween); sp.Start(); for (int i = 0; i < ari3.Count; i++) fill = ari3[i]; sp.Stop(); ar3Time += sp.ElapsedMilliseconds;
fill = 0; sp.Reset(); Thread.Sleep(SleepTimeInBetween); sp.Start(); foreach (int i in ari4) fill = ari4[i]; sp.Stop(); ar4Time += sp.ElapsedMilliseconds;
fill = 0; sp.Reset(); Thread.Sleep(SleepTimeInBetween); sp.Start(); for (int i = 0; i < ari5.Length; i++) fill = ari5[i]; sp.Stop(); ar5Time += sp.ElapsedMilliseconds;
fill = 0; sp.Reset(); Thread.Sleep(SleepTimeInBetween); sp.Start(); foreach (int i in ari6) fill = ari6[i]; sp.Stop(); ar6Time += sp.ElapsedMilliseconds; fill = 0; }
static void ObjectCheck() { Stopwatch sp = new Stopwatch(); int fill = 0;
if (arl1 == null || arl1.Count != objectsToTest) { arl1 = null; arl1 = new ArrayList(objectsToTest); } if (arl2 == null || arl2.Count != objectsToTest) { arl2 = null; arl2 = new ArrayList(objectsToTest); } if (arl3 == null || arl3.Count != objectsToTest) { arl3 = null; arl3 = new List<BoringObjectClass>(objectsToTest); } if (arl4 == null || arl4.Count != objectsToTest) { arl4 = null; arl4 = new List<BoringObjectClass>(objectsToTest); } if (arl5 == null || arl5.Length != objectsToTest) { arl5 = null; arl5 = new BoringObjectClass[objectsToTest]; } if (arl6 == null || arl6.Length != objectsToTest) { arl6 = null; arl6 = new BoringObjectClass[objectsToTest]; }
while (fill < objectsToTest) { arl1.Add(new BoringObjectClass(fill)); arl2.Add(new BoringObjectClass(fill)); arl3.Add(new BoringObjectClass(fill)); arl4.Add(new BoringObjectClass(fill)); arl5[fill] = new BoringObjectClass(fill); arl6[fill] = new BoringObjectClass(fill);
fill++; }
fill = 0; sp.Reset(); Thread.Sleep(SleepTimeInBetween); sp.Start(); for (int i = 0; i < arl1.Count; i++) fill = (arl1[i] as BoringObjectClass).SomeInt; sp.Stop(); ar1Time += sp.ElapsedMilliseconds;
fill = 0; sp.Reset(); Thread.Sleep(SleepTimeInBetween); sp.Start(); foreach (BoringObjectClass i in arl2) fill = i.SomeInt; sp.Stop(); ar2Time+= sp.ElapsedMilliseconds;
fill = 0; sp.Reset(); Thread.Sleep(SleepTimeInBetween); sp.Start(); for (int i = 0; i < arl3.Count; i++) fill = arl3[i].SomeInt; sp.Stop(); ar3Time += sp.ElapsedMilliseconds;
fill = 0; sp.Reset(); Thread.Sleep(SleepTimeInBetween); sp.Start(); foreach (BoringObjectClass i in arl4) fill = i.SomeInt; sp.Stop(); ar4Time += sp.ElapsedMilliseconds;
fill = 0; sp.Reset(); Thread.Sleep(SleepTimeInBetween); sp.Start(); for (int i = 0; i < arl5.Length; i++) fill = arl5[i].SomeInt; sp.Stop(); ar5Time += sp.ElapsedMilliseconds;
fill = 0; sp.Reset(); Thread.Sleep(SleepTimeInBetween); sp.Start(); foreach (BoringObjectClass i in arl6) fill = i.SomeInt; sp.Stop(); ar6Time += sp.ElapsedMilliseconds; fill = 0; }
static void BeginIntCheck() { int illiterations = 0;
while (true) { Console.WriteLine(); Console.WriteLine(); Console.WriteLine("Integer Test."); Console.WriteLine("Press: Enter to run [n] times. R to average [n] times. A to add [n] times. Escape to go back."); ar1Time = 0; ar2Time = 0; ar3Time = 0; ar4Time = 0; ar5Time = 0; ar6Time = 0; builder = new StringBuilder();
switch (Console.ReadKey().Key) { case ConsoleKey.Enter: intsToTest = GetCount(); Console.WriteLine(); Console.WriteLine("Running... This may take a few minutes.");
IntCheck();
builder.AppendLine("Int Test Results"); builder.AppendLine("FOR loop time on ArrayList with " + intsToTest + " items:"); builder.AppendLine("Elapsed Milliseconds: " + ar1Time); builder.AppendLine("FOREACH loop time on ArrayList with " + intsToTest + " items:"); builder.AppendLine("Elapsed Milliseconds: " + ar2Time); builder.AppendLine("FOR loop time on generic collection with " + intsToTest + " items:"); builder.AppendLine("Elapsed Milliseconds: " + ar3Time); builder.AppendLine("FOREACH loop time on generic collection with " + intsToTest + " items:"); builder.AppendLine("Elapsed Milliseconds: " + ar4Time); builder.AppendLine("FOR loop time on array with " + intsToTest + " items:"); builder.AppendLine("Elapsed Milliseconds: " + ar5Time); builder.AppendLine("FOREACH loop time on array with " + intsToTest + " items:"); builder.AppendLine("Elapsed Milliseconds: " + ar6Time); LogIt();
builder.Remove(0, builder.Length); builder = null;
break; case ConsoleKey.A: intsToTest = GetCount(); Console.WriteLine(); illiterations = GetIlliterations(); Console.WriteLine(); Console.WriteLine("Running... This may take a few minutes.");
for (int i = 0; i < illiterations; i++) IntCheck();
builder.AppendLine("Int Test Results"); builder.AppendLine("FOR loop time on ArrayList with " + intsToTest + " items looped " + illiterations + " times:"); builder.AppendLine("Total Elapsed Milliseconds: " + ar1Time); builder.AppendLine("FOREACH loop time on ArrayList with " + intsToTest + " items looped " + illiterations + " times:"); builder.AppendLine("Total Elapsed Milliseconds: " + ar2Time); builder.AppendLine("FOR loop time on generic collection with " + intsToTest + " items looped " + illiterations + " times:"); builder.AppendLine("Total Elapsed Milliseconds: " + ar3Time); builder.AppendLine("FOREACH loop time on generic collection with " + intsToTest + " items looped " + illiterations + " times:"); builder.AppendLine("Total Elapsed Milliseconds: " + ar4Time); builder.AppendLine("FOR loop time on array with " + intsToTest + " items looped " + illiterations + " times:"); builder.AppendLine("Total Elapsed Milliseconds: " + ar5Time); builder.AppendLine("FOREACH loop time on array with " + intsToTest + " items looped " + illiterations + " times:"); builder.AppendLine("Total Elapsed Milliseconds: " + ar6Time); LogIt();
builder.Remove(0, builder.Length); builder = null;
break; case ConsoleKey.R: intsToTest = GetCount(); Console.WriteLine(); illiterations = GetIlliterations(); Console.WriteLine(); Console.WriteLine("Running... This may take a few minutes.");
for (int i = 0; i < illiterations; i++) IntCheck();
builder.AppendLine("Int Test Results"); builder.AppendLine("FOR loop time on ArrayList with " + intsToTest + " items looped " + illiterations + " times:"); builder.AppendLine("Average Elapsed Milliseconds: " + ( ar1Time / (decimal) illiterations )); builder.AppendLine("FOREACH loop time on ArrayList with " + intsToTest + " items looped " + illiterations + " times:"); builder.AppendLine("Average Elapsed Milliseconds: " + ( ar2Time / (decimal) illiterations )); builder.AppendLine("FOR loop time on generic collection with " + intsToTest + " items looped " + illiterations + " times:"); builder.AppendLine("Average Elapsed Milliseconds: " + ( ar3Time / (decimal) illiterations )); builder.AppendLine("FOREACH loop time on generic collection with " + intsToTest + " items looped " + illiterations + " times:"); builder.AppendLine("Average Elapsed Milliseconds: " + ( ar4Time /(decimal) illiterations )); builder.AppendLine("FOR loop time on array with " + intsToTest + " items looped " + illiterations + " times:"); builder.AppendLine("Average Elapsed Milliseconds: " + ( ar5Time / (decimal) illiterations )); builder.AppendLine("FOREACH loop time on array with " + intsToTest + " items looped " + illiterations + " times:"); builder.AppendLine("Average Elapsed Milliseconds: " + ( ar6Time / (decimal) illiterations )); builder.AppendLine(); LogIt();
builder.Remove(0, builder.Length); builder = null;
break; case ConsoleKey.Escape: return; default: break; } } }
static void BeginObjCheck() { int illiterations = 0;
while (true) { Console.WriteLine(); Console.WriteLine(); Console.WriteLine("Object Test."); Console.WriteLine("Press: Enter to run [n] times. R to average [n] times. A to add [n] times. Escape to go back.");
ar1Time = 0; ar2Time = 0; ar3Time = 0; ar4Time = 0; ar5Time = 0; ar6Time = 0; builder = new StringBuilder();
switch (Console.ReadKey().Key) { case ConsoleKey.Enter: objectsToTest = GetCount(); Console.WriteLine(); Console.WriteLine("Running... This may take a few minutes.");
ObjectCheck();
builder.AppendLine("Object Test Results"); builder.AppendLine("FOR loop time on ArrayList with " + objectsToTest + " items:"); builder.AppendLine("Elapsed Milliseconds: " + ar1Time); builder.AppendLine("FOREACH loop time on ArrayList with " + objectsToTest + " items:"); builder.AppendLine("Elapsed Milliseconds: " + ar2Time); builder.AppendLine("FOR loop time on generic collection with " + objectsToTest + " items:"); builder.AppendLine("Elapsed Milliseconds: " + ar3Time); builder.AppendLine("FOREACH loop time on generic collection with " + objectsToTest + " items:"); builder.AppendLine("Elapsed Milliseconds: " + ar4Time); builder.AppendLine("FOR loop time on array with " + objectsToTest + " items:"); builder.AppendLine("Elapsed Milliseconds: " + ar5Time); builder.AppendLine("FOREACH loop time on array with " + objectsToTest + " items:"); builder.AppendLine("Elapsed Milliseconds: " + ar6Time); LogIt();
builder.Remove(0, builder.Length); builder = null;
break; case ConsoleKey.A: objectsToTest = GetCount(); Console.WriteLine(); illiterations = GetIlliterations(); Console.WriteLine(); Console.WriteLine("Running... This may take a few minutes.");
for (int i = 0; i < illiterations; i++) ObjectCheck();
builder.AppendLine("Object Test Results"); builder.AppendLine("FOR loop time on ArrayList with " + objectsToTest + " items looped " + illiterations + " times:"); builder.AppendLine("Total Elapsed Milliseconds: " + ar1Time); builder.AppendLine("FOREACH loop time on ArrayList with " + objectsToTest + " items looped " + illiterations + " times:"); builder.AppendLine("Total Elapsed Milliseconds: " + ar2Time); builder.AppendLine("FOR loop time on generic collection with " + objectsToTest + " items looped " + illiterations + " times:"); builder.AppendLine("Total Elapsed Milliseconds: " + ar3Time); builder.AppendLine("FOREACH loop time on generic collection with " + objectsToTest + " items looped " + illiterations + " times:"); builder.AppendLine("Total Elapsed Milliseconds: " + ar4Time); builder.AppendLine("FOR loop time on array with " + objectsToTest + " items looped " + illiterations + " times:"); builder.AppendLine("Total Elapsed Milliseconds: " + ar5Time); builder.AppendLine("FOREACH loop time on array with " + objectsToTest + " items looped " + illiterations + " times:"); builder.AppendLine("Total Elapsed Milliseconds: " + ar6Time); LogIt();
builder.Remove(0, builder.Length); builder = null;
break; case ConsoleKey.R: objectsToTest = GetCount(); Console.WriteLine(); illiterations = GetIlliterations(); Console.WriteLine(); Console.WriteLine("Running... This may take a few minutes.");
for (int i = 0; i < illiterations; i++) ObjectCheck();
builder.AppendLine("Object Test Results"); builder.AppendLine("FOR loop time on ArrayList with " + objectsToTest + " items looped " + illiterations + " times:"); builder.AppendLine("Average Elapsed Milliseconds: " + ( ar1Time / (decimal) illiterations )); builder.AppendLine("FOREACH loop time on ArrayList with " + objectsToTest + " items looped " + illiterations + " times:"); builder.AppendLine("Average Elapsed Milliseconds: " + ( ar2Time / (decimal) illiterations )); builder.AppendLine("FOR loop time on generic collection with " + objectsToTest + " items looped " + illiterations + " times:"); builder.AppendLine("Average Elapsed Milliseconds: " + ( ar3Time / (decimal) illiterations )); builder.AppendLine("FOREACH loop time on generic collection with " + objectsToTest + " items looped " + illiterations + " times:"); builder.AppendLine("Average Elapsed Milliseconds: " + ( ar4Time /(decimal) illiterations )); builder.AppendLine("FOR loop time on array with " + objectsToTest + " items looped " + illiterations + " times:"); builder.AppendLine("Average Elapsed Milliseconds: " + ( ar5Time / (decimal) illiterations )); builder.AppendLine("FOREACH loop time on array with " + objectsToTest + " items looped " + illiterations + " times:"); builder.AppendLine("Average Elapsed Milliseconds: " + ( ar6Time / (decimal) illiterations )); builder.AppendLine(); LogIt();
builder.Remove(0, builder.Length); builder = null;
break; case ConsoleKey.Escape: return; default: break; } } }
static int GetCount() { while (true) { Console.WriteLine(); Console.WriteLine("How many elements to check?"); Console.WriteLine("Enter 0 to use the default of int.MaxValue / 1000.");
int iElements = 0; if (int.TryParse(Console.ReadLine(), out iElements)) { if (iElements > 0) return iElements; else if (iElements == 0) return int.MaxValue / 1000; } } }
static int GetIlliterations() { while (true) { Console.WriteLine(); Console.WriteLine("How many illiterations?");
int iIlliterations = 0; if (int.TryParse(Console.ReadLine(), out iIlliterations)) { if (iIlliterations > 0) return iIlliterations; } } }
static void LogIt() { if (SaveToLog && builder.Length > 0) { StreamWriter wrt = null;
try { wrt = new StreamWriter(LogFileName, AppendLog);
foreach (string L in builder.ToString().Split(sp)) if (L.Length > 0) { Console.WriteLine(L); wrt.WriteLine(L); } } finally { if (wrt != null) { wrt.Close(); wrt = null; } } } else foreach (string L in builder.ToString().Split(sp)) if (L.Length > 0) Console.WriteLine(L); }
static void Main(string[] args) { Console.WriteLine("FOREACH VS FOR CHECK");
while (true) { Console.WriteLine(); Console.WriteLine("Press: O to test with objects. I to test with integers. Escape to exit.");
switch (Console.ReadKey().Key) { case ConsoleKey.O: BeginObjCheck(); break; case ConsoleKey.I: BeginIntCheck(); break; case ConsoleKey.Escape: return; } }
} } }
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Misleading and irrelevant statements by an author without even basic understanding about programming.
|
| Sign In·View Thread·PermaLink | 1.00/5 |
|
|
|
 |
|
|
 |
|
 |
You say:
" foreach copies the current array to a new one "
I don't see where in the IL it does that.
And have you retested with newer versions?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
The article gives very false information. Here is the truth.
For-Each loop is always slower then a plain for loop. In case of a For loop the CX register is loaded with the highest value (or the reverse) and then after every iteration the CX register is incremented/decremented. thats not much work.
The For-Each loop it is just a language construct that translates something that is closer to a while loop. For-each works only on objects that support IEnumerable. The object is first queried for the IEnumeable which returns an IEnumerator which exposes functions like Next, Reset, Item, Count etc. For loop works by calling these functions repeatedly. a function call is almost always expensive and results in a lot of work (pushing registers on stack, saving return address etc).
I'm not sure if the .NET compiler expands the for-each function inline. If it does then the speed is slightly increased but the plain for loop is almost always the winner.
Second thing is when you are checking the code execution speed the coding timers can never give the correct results. as there might be many factors effecting the performance. The correct way to measure the speed of code is by using the appropiate profiler.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
With release builds using Visual Studio 2005, foreach is FASTER than for.
This simple test program demonstrates it:
private void button1_Click_1(object sender, EventArgs e) { Stopwatch stopwatch = new Stopwatch();
int[] array = new int[10000000];
stopwatch.Start(); Test1(array); stopwatch.Stop(); MessageBox.Show("Elapsed 1 = " + stopwatch.ElapsedMilliseconds);
stopwatch.Reset(); stopwatch.Start(); Test2(array); stopwatch.Stop(); MessageBox.Show("Elapsed 2 = " + stopwatch.ElapsedMilliseconds); }
int Test1(int[] array) { int total = 0;
for (int i = 0; i < array.Length; ++i) total += array[i];
return total; }
int Test2(int[] array) { int total = 0;
foreach (int value in array) total += value;
return total; }
Results on my system (release build):
for loop: 41 ms foreach loop: 18 ms
So the foreach loop is MORE THAN TWICE AS FAST as the for loop.
Time to put this one to bed and STOP TELLING PEOPLE STUFF THAT'S JUST PLAIN WRONG!
|
| Sign In·View Thread·PermaLink | 4.00/5 |
|
|
|
 |
|
 |
It sounds like you have a vendetta with a minor foreach misconception. It is probably true that foreach is faster than (or at least as fast as) a for loop when working with arrays.
You are both missing the bigger picture, though. When working with other types of collections, how foreach actually works is up to the designer of the collection class: the person who implements IEnumerator. When you consider that, well, there really is not way to say which is faster. Besides, even when working with arrays, the speed will to some extent depend on how you use the value, but what will be even more important 9 out of 10 times is that when using a for loop you have access to the index of the item you are examining and when using a foreach loop the code will usually be simpler. Use the method that results in the simplest code. If performance is a serious issue, you should try a few variants and see which is best, rather than depending on a generalization.
|
| Sign In·View Thread·PermaLink | 5.00/5 |
|
|
|
 |
|
 |
That's fair enough - my beef is with saying that foreach is slower when it isn't. You have to instrument things!
I in fact made an error with my test program that I posted above.
I should have put the two tests in a loop that ran for 100 or more iteration to eliminate distortions caused by JIT.
If you do so, it turns out that foreach is only marginally faster than for, not twice as fast.
However, it is certainly not slower. 
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Not a good test, reverse the test in your code, test array 2 first and then test array 1. The for is more than twice as fast as the foreach. Maybe its your test code thats wrong?
He who laughs last thinks slowest.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
What you will find is the C# compiler doesnt use the enumerator pattern when working on arrays - a simple look at the IL will show this.
private static void EnumerationExample() { int[] ints = new int[50];
foreach(int i in ints) { int p = 0; p = i + p; }
Console.WriteLine("A");
List ints2 = new List(new int[50]);
foreach (int i in ints2) { int p = 0; p = i + p; } }
In a pretty decent programmatic profiling framework I have written I can prove that on average the normal for-loop is over 3x quicker (with the normal caveats on performance related issues associated with profiling in a managed environment). Iterating a loop with 1000000 items in it, 100 times shows me on my box that the enumeration on average takes 112 milliseconds, while the for-each only takes 35. Clearly marginal in most simple situations, but definitely worth considering when building real-time applications...you must also consider the impact of the GC for the new enumeration objects in the non-for-loop example.
Nick. www.lab49.com
|
| Sign In·View Thread·PermaLink | 2.67/5 |
|
|
|
 |
|
 |
The point of for each is that you don't need to know how the object works to iterate through it. OK the performance is a teeny weeny bit slower (but very very unlikely to be a bottleneck) but the advantage is that if you swap the array for another container type which doesn't use numerical indexes then you don't need to change any code.
|
| Sign In·View Thread·PermaLink | 5.00/5 |
|
|
|
 |
|
 |
First, without actually benchmarking a section of assembly, any conclusions about its performance on modern processors can only be ballpark in nature; with caching, deep pipelines, branch predicting, etc. code may actually be faster than it first appears.
Second, the code in your 'for' example is missing an add dword ptr [ecx+8],eax instruction. The 'foreach' example appears to be based on debug IDL, not optimized IDL (though that's only speculation; but my results differ from what it shown.)
Third, in the 'foreach' example (using my optimized assembly), the redundant check is used only the first time through. From then on it branches back to the mov eax... instruction (just after the jb instruction. In my optimized version, this extra code isn't present.)
In my code, the only substantial difference between two algorithms is the 'for' loop has an extra bounds check at the top of the loop (to throw, I presume, an out-of-bounds exception should the need arise.)
Finally, I have done many benchmarks with 'for' and 'foreach'. 'foreach' is almost always faster. I've concluded that 'for' should be used if you need to modify the contents of the array and/or you need to readily know the index of an item. Otherwise, foreach is usually a better choice. But, as always, if performance is a concern, benchmark both and even consider other possibilities which may be even faster and/or more efficient.
PS. I know 80x86 assembly extremely well. For several years I had a job where everything was written in 80x86 assembly (I've also done 6502 and 68000 assembly professionally and some Z80 on the side.)
Anyone who thinks he has a better idea of what's good for people than people do is a swine. - P.J. O'Rourke
|
| Sign In·View Thread·PermaLink | 5.00/5 |
|
|
|
 |
|
 |
For very large numbers of iterations (and this is important, because for small iterations the setup and tear-down portions of a loop become significant percentages for the loop processing time) you could try:
try { for(int i = myVeryLargeArray.Length; ; i--) { } } catch { }
Notice that there is no exit condition check in the for statement. So, what happens when i becomes -1?
** BANG ** IndexOutOfRangeException
For VERY LARGE numbers of iterations the cost of the exception can be cheaper than the cost of an exit condition check on each iteration.
"You can have everything in life you want if you will just help enough other people get what they want." --Zig Ziglar
Coming soon: The Second EuroCPian Event[^].
|
| Sign In·View Thread·PermaLink | 4.33/5 |
|
|
|
 |
|
 |
paulb wrote: Sorry, but I think this is just totally ugly
Don't appologies. It is ugly. I never said otherwise.
paulb wrote: You are using exception handling as a method of normally exiting a loop
Yes, that was the point of my post.
"You can have everything in life you want if you will just help enough other people get what they want." --Zig Ziglar
Coming soon: The Second EuroCPian Event
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
 |
|
|
 |
|
 |
What is the cost of performing a bounds check in each loop. In other words what is the difference between:
for(int i = 0; i<largeArrayUpperBound; i++) { } and
for(int i = 0; ; i++) { }
So what is the difference cost over millions of cycles?
Since an exception is thrown anyway when the index of the array is out of bounds (we can infer that a bounds check is performed when you access the array's indexer) so why duplicate the effort? Why not just wait for the exception to be thrown and catch it?
Like I said somewhere else, I'm not crazy to actually put this in a production environment as you need to be able to say that consistently you will have all those millions of cycles each time this code is executed. But from an academic point of view it is interesting to see what happens.
"You can have everything in life you want if you will just help enough other people get what they want." --Zig Ziglar
Coming soon: The Second EuroCPian Event
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
And also its not a good thing to allow throwing exception. Another thing,
for(int i=0; i < myArray.Length; i++){} is equal to
for(int i=0; i < arrayLength; i++){} after JIT compiled.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Norm Almond wrote: allowing the clr to throw exceptions can also be VERY time consuming
That is why you need to have millions of cycles in the iteration, otherwise it is just not worth it.
"You can have everything in life you want if you will just help enough other people get what they want." --Zig Ziglar
Coming soon: The Second EuroCPian Event
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi Colin,
Exception is not for capturing one bad written logic. Exception is for capturing unexpected logical error.
Beside Exception captured slow down program running a lot.
Therefore, programmer needs to determine when is the time to use try...catch
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Like I've said elsewhere in this thread. This is only an academic excercise. I don't expect to ever use or see this anywhere in production code, simply because you need to guarantee that there will be sufficient numbers of iterations in advance. For some actual statistics go here[^]
"You can have everything in life you want if you will just help enough other people get what they want." --Zig Ziglar
The Second EuroCPian Event will be in Brussels on the 4th of September
Can't manage to P/Invoke that Win32 API in .NET? Why not do interop the wiki way!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hmmm...what is wrong with this logic???
>>>>>>>>>>>>>> Exception is not for capturing one bad written logic. Exception is for capturing unexpected logical error. Beside Exception captured slow down program running a lot. Therefore, programmer needs to determine when is the time to use try...catch >>>>>>>>>>>>>>
Ex = Exception BL = Bad Logic ULE = Unexpected Logical Error(s) SP = Slows Program PR = PRogrammer TC = Try/Catch ~ = NOT
Premise: Ex --> ~BL Premise: Ex --> ULE Premise: Ex --> SP _____________________________ Conclusion: P --> (TC or ~TC) Contrapositive: (~TC and TC) --> ~P
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
There is a major misunderstanding on your part here. Both of the above code listings are less than desirable. The ideal code listing would be in the form of:
for(int i = 0; i < array.Length; i++) { }
The important thing here is that you use the Length property of the array in the terminating condition. When you do this, the JIT compiler can infer that you are iterating over an array and bounds checks (the bounds checks that are performed each time you access the array within the loop) can be eliminated. What's more, the compiler knows that the array bounds are immutable, so it will optimize away the property getter function call that you have coded into the terminating condition. The result? Code that executes, at worst, the same speed as your "optimized" code, or faster if there are more than one array accesses in the loop, minus the cost of an exception (which can be quite exceptional if it is the first exception thrown by the application), plus more readable code. The moral of the story? Don't try to micro-optimize your dot-net code. The JIT compiler is smarter than you think, and unless you know all the nuances it is hard to out-smart it.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |