Click here to Skip to main content
Click here to Skip to main content

FOREACH Vs. FOR (C#)

By , 19 Apr 2004
 

Introduction

In my experience, there are two kinds of programmers. Those who write something to get the work done and those who want to write good code. But, here we get a big question. What is good code? Good code comes from good programming practices. What are good programming practices? Actually, my aim here is not to talk about good programming practices (I’m planning to write something related to that in future!), rather to talk more about writing something which will be more effective. I'm only going to look more deeper of two loops which are commonly used nowadays, and their differences in the aspect of performance.

Background

Must be familiar with IL and assembly code. Also, better to have a good knowledge on how .NET framework works. Some knowledge of JIT is also needed to understand what is exactly happening.

Using the code

I’m going to take a very small piece of code for two popular looping statements for and foreach. We will look some code and will see what it does, more in detail about the functionality.

FOR

int[] myInterger = new int[1];
int total = 0;
for(int i = 0; i < myInterger.Length; i++)
{
    total += myInterger[i];
}

foreach

int[] myInterger = new int[1];
int total = 0;
foreach(int i in myInterger) 
{
    total += i;
}

Both codes will produce the same result. foreach is used on top of collections to traverse through while for can be used on anything for the same purpose. I’m not going to explain whatsoever about the code. Before going in more deeper, I think all of you are familiar with ILDasm which is used to generate IL code, and CorDbg tool which is normally used to generate JIT compiled code.

The IL code produced by C# compiler is optimized up to certain extend, while leaving some part to JIT. Anyway, this is not really what matters to us. So, when we talk about the optimization, two things we must consider. First is C# compiler and the second is JIT.

So, rather than looking more deep into IL code, we will see more about the code which is emitted by JIT. That is the code which will run on our machine. I’m now using AMD Athlon 1900+. The code highly depends on our hardware. Therefore, what you may get from your machine may differ from mine up to a certain extend. Anyway, the algorithms wont change that much.

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.

Here, I’m going into the exact difference between the codes.

FOR

Instruction                           Effect
cmp     dword ptr [eax+4],0           i<myInterger.Length
jle     0000000F
mov     ecx,dword ptr [eax+edx*4+8]   total += myInterger[i]
inc     edx                           ++i
cmp     esi,dword ptr [eax+4]         i<myInterger.Length
jl      FFFFFFF8

I’ll explain what is happening here. The esi register which holds the value of i and the length of myInteger array are compared at two stages. The first one is done only once to check the condition and if the loop can continue, the value is added. For the loop, it is done at the second stage. Inside the loop, it is well optimized and as explained, the work is done with perfect optimization.

foreach

Instruction                            Effect
cmp     esi,dword ptr [ebx+4]          i<myInterger.Length
jl      FFFFFFE3
cmp     esi,dword ptr [ebx+4]          i<myInterger.Length 
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          total += i
inc     esi                            ++i
cmp     esi,dword ptr [ebx+4]          i<myInterger.Length
jl      FFFFFFE3

Anyone will say that both are not the same. But we will look why it differs from the for loop. The main reason for the difference is that both of them are differently understood by the compiler. The algorithm they are using is different. Two compare statements one after the other is unnecessary. It is doing the same thing again and again for no reason!

cmp                    esi,dword ptr [ebx+4]   
jl                         FFFFFFE3
cmp                    esi,dword ptr [ebx+4]

It also uses some unnecessary move statements which also may (not always, but depends) reduce the performance of the code. foreach is thinking everything as a collection and treating them as a collection. I feel, that will also reduce the performance of the work.

Therefore, I strongly feel if you are planning to write high performance code that is not for collections, use for loop. Even for collections, foreach may look handy when using, but it's not that efficient. Therefore, I strongly recommend everyone to use for loop rather than foreach at any stage.

Points of Interest

Actually, I did a small research on the performance issue of codes mainly on .NET languages. While I was testing, I found that it was really a must to know how JIT works and to debug the code generated by JIT compiler. It took some time to understand the code.

History

This is submitted on 19th of April 2004.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Chester Ragel
Web Developer
Singapore Singapore
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Suggestionforeach loop is better than for loopmemberabiruban16 Mar '13 - 21:33 
GeneralMy vote of 1memberKamyar29 Jan '13 - 5:23 
GeneralFor Vs Foreach - Benchmark 2013 [modified]mvpadriancs21 Jan '13 - 19:21 
GeneralMy vote of 1memberRutgerStorm10 Jan '13 - 0:23 
GeneralMy vote of 1memberSnorri9 Jan '13 - 2:30 
QuestionBetter to avoid using ForEach statementsmemberMember 42640614 Oct '12 - 20:27 
GeneralMy vote of 5memberkevinprasannan6 Jul '12 - 23:50 
QuestionListen to the manmembermsdevtech2 Jul '12 - 2:16 
AnswerRe: Listen to the manmemberRutgerStorm10 Jan '13 - 0:07 
GeneralMy vote of 5memberMember 85055188 Feb '12 - 18:13 
QuestionAlternatives to Loopingmembermalcolmvr15 Dec '11 - 7:14 
GeneralMy vote of 1memberakjoshi11 Dec '11 - 23:59 
Answer[My vote of 1] ForEach is for Objects [modified]membersekhar Aripaka3 May '11 - 17:40 
ForEach works efficiently for Objects not for primitive data types like int.,
 
I have tested this with 1 million objects and see ForEach is running 20-25% faster than For...
Run this code and see for yourself...
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace ForVsForEach
{
    class Program
    {
        static void Main(string[] args)
        {
            EmployeeCollection<Employee> ec = new EmployeeCollection<Employee>();
            int maxItems = 1000000;
            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            Console.WriteLine("Loading employee objects...");
            sw.Start();
            for (int i = 0; i < maxItems; i++)
            {
                ec.Add(new Employee(i.ToString(),i));
            }
            sw.Stop();
            Console.WriteLine(string.Format("Done loading {0} employee objects. Time lapsed {1} Milliseconds.", maxItems.ToString(), sw.Elapsed.TotalMilliseconds.ToString()));
            Console.ReadLine();
 
            Console.WriteLine("Reading employee objects using for() loop...");
            sw.Restart();//Available in FW 4.0 - for FW3.5 use sw.Reset();sw.Start();
            for (int i = 0; i < maxItems; i++)
            {
                string name = ec.Get(i).Name;
            }
            sw.Stop();
            Console.WriteLine(string.Format("Done reading {0} employee objects using for() loop. Time lapsed {1} Milliseconds.", maxItems.ToString(), sw.Elapsed.TotalMilliseconds.ToString()));
            Console.ReadLine();
 
            Console.WriteLine("Reading employee objects using ForEach() loop...");
            sw.Restart();//Available in FW 4.0 - for FW3.5 use sw.Reset();sw.Start();
            foreach (Employee e in ec.Items)
            {
                string name = e.Name;
            }
            sw.Stop();
            Console.WriteLine(string.Format("Done reading {0} employee objects using ForEach() loop. Time lapsed {1} Milliseconds.", maxItems.ToString(), sw.Elapsed.TotalMilliseconds.ToString()));
            Console.ReadLine();
 
            ec.Clear();
        }
    }
 

 
    class Employee
    {
        public Employee(string name,int salary)
        {
            this.Name = name;
            this.Salary = salary;
        }
 
        public string Name { get; set; }
        public int Salary{ get; set; } 
    }
 
    public class EmployeeCollection<T> 
    {
        private List<T> ar = new List<T>();
 
        public T Get(int pos)
        { return ar[pos]; }
 
        public void Add(T c)
        { ar.Add(c); }
 
        public void Clear()
        { ar.Clear(); }
 
        public int Count
        { get { return ar.Count; } }
 
        public List<T> Items
        { get { return ar; } }
 
    }
 
}
 

modified on Wednesday, May 4, 2011 3:07 PM

GeneralMy vote of 1memberStein Gregory24 Apr '11 - 22:05 
GeneralFOREACH vs FOR, tested again. FOR wins.memberbluedog says3 Jun '09 - 10:44 
GeneralRe: FOREACH vs FOR, tested again. FOR wins.mvpadriancs22 Jan '13 - 20:57 
GeneralMy vote of 1memberiosgmbh14 Apr '09 - 20:52 
Generallink to a correct articlememberkorsuas16 May '08 - 0:15 
Generalforeach copies the current array to a new onememberPIEBALDconsult15 May '08 - 9:43 
GeneralTechnical Detailsmembermercede19 Nov '07 - 22:16 
GeneralArticle is out of date and now INCORRECTmemberHis Divine Shadow26 Feb '07 - 23:31 
GeneralRe: Article is out of date and now INCORRECTmembersnarfblam27 Feb '07 - 15:45 
GeneralRe: Article is out of date and now INCORRECTmemberHis Divine Shadow28 Feb '07 - 0:14 
GeneralRe: Article is out of date and now INCORRECTmemberThe Limey6 Apr '07 - 22:00 
GeneralRe: Article is out of date and now INCORRECTmemberNiclars5 Jul '07 - 0:10 
GeneralRe: Article is out of date and now INCORRECTmembermsdevtech2 Jul '12 - 2:41 
GeneralMissing the pointmemberhamacatak9 Aug '06 - 4:10 
GeneralA counterpoint to this articlememberJoe Woodbury3 Dec '04 - 7:10 
GeneralHave you considered....memberColin Angus Mackay20 Apr '04 - 11:43 
GeneralRe: Have you considered....memberColin Angus Mackay20 Apr '04 - 20:43 
GeneralRe: Have you considered....memberNorm Almond20 Apr '04 - 21:35 
GeneralRe: Have you considered....memberColin Angus Mackay20 Apr '04 - 22:11 
GeneralRe: Have you considered....memberChester Ragel20 Apr '04 - 22:15 
GeneralRe: Have you considered....memberColin Angus Mackay20 Apr '04 - 22:59 
GeneralRe: Have you considered....memberNorm Almond21 Apr '04 - 1:15 
GeneralRe: Have you considered....memberChester Ragel21 Apr '04 - 1:22 
GeneralRe: Have you considered....memberColin Angus Mackay21 Apr '04 - 1:48 
GeneralRe: Have you considered....memberdanny2138453 Jun '04 - 18:47 
GeneralRe: Have you considered....memberColin Angus Mackay3 Jun '04 - 19:56 
GeneralRe: Have you considered....memberJohnLWhitaker14 Jun '07 - 7:53 
GeneralRe: Have you considered....memberLimitedAtonement1 Dec '09 - 5:21 
GeneralRe: Have you considered....membersnarfblam27 Feb '07 - 15:55 
GeneralRe: Have you considered....mvpColin Angus Mackay27 Feb '07 - 21:53 
GeneralRe: Have you considered....membersnarfblam2 Mar '07 - 11:28 
GeneralRe: Have you considered....memberPlayByTheRules12 Mar '07 - 0:59 
GeneralRe: Have you considered....membersnarfblam14 Mar '07 - 13:23 
GeneralRe: Have you considered....memberLimitedAtonement1 Dec '09 - 5:29 
GeneralRe: Have you considered....mvpColin Angus Mackay1 Dec '09 - 5:33 
GeneralRe: Have you considered....memberChester Ragel20 Apr '04 - 21:34 
GeneralRe: Have you considered....memberColin Angus Mackay20 Apr '04 - 22:23 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 20 Apr 2004
Article Copyright 2004 by Chester Ragel
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid