November 2, 2013

For vs Foreach in Performance Meter

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 is question about to show the best performance and it would come when you write a Good Code. So, What is good code? Good code comes from good programming practices. Here I'm showing you the comparision between two popular loops to show which one is best in performance. 

The demonstration will include the IL and assembly code, you must be familiar with them. Also have a good knowledge on how .Net framework works. Some knowledge of JIT is also needed to understand what is exactly happening.

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. So, when we talk about the optimization, two things we must consider. First is C# compiler and the second is JIT.

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

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 reduce the performance of the code. Foreach is thinking everything as a collection and treating them as a collection. That will also reduce the performance of the work. 

Therefore, 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. Cheers

No comments:

Post a Comment