Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does IF perform better than IF-ELSE?

Which one of these blocks of code performs better, and which one of them is more readable? I'd guess the gain would be negligible, particularly in the second block. I am just curious.

Block #1

string height; string width; if (myFlag == 1) {     height = "60%";     width = "60%"; } else {     height = "80%";     width = "80%"; } 

Block #2

string height = "80%"; string width = "80%"; if (myFlag == 1) {     height = "60%";     width = "60%"; } 

Updated

The results when i tested the above code were that both the blocks performed the same

Block #1

myFlag = 1:   3 Milliseconds myFlag = 0:   3 Milliseconds 

Block #2

myFlag = 1:   3 Milliseconds myFlag = 0:   3 Milliseconds 

But one important thing i noticed here(thanks to Matthew Steeples answer here) is that since the block of code that i have tested has not used the variables height and width except for assignment in the if-else and if blocks of Code Block-1 and 2 respectively, the compiler has optimized the IL code by completely removing the if and if-else blocks in question thus showing invalid results for our test here.

I have updated both the code blocks to write the values of both height and width to a file thus using them again and forcing the compiler to run our test blocks(I hope), but you can observe from the code that the actual file writing part does not effect our test results

This is the updated results, C# and IL Code

Results

Block #1

myFlag = 1:   1688 Milliseconds myFlag = 0:   1664 Milliseconds 

Block #2

myFlag = 1:   1700 Milliseconds myFlag = 0:   1677 Milliseconds 

C#.net Code

Block #1

    public long WithIfAndElse(int myFlag)     {         Stopwatch myTimer = new Stopwatch();         string someString = "";         myTimer.Start();         for (int i = 0; i < 1000000; i++)         {             string height;             string width;             if (myFlag == 1)             {                 height = "60%";                 width = "60%";             }             else             {                 height = "80%";                 width = "80%";             }             someString = "Height: " + height + Environment.NewLine + "Width: " + width;         }         myTimer.Stop();         File.WriteAllText("testifelse.txt", someString);         return myTimer.ElapsedMilliseconds;     } 

Block #2

    public long WithOnlyIf(int myFlag)     {          Stopwatch myTimer = new Stopwatch();         string someString = "";         myTimer.Start();         for (int i = 0; i < 1000000; i++)         {             string height = "80%";             string width = "80%";             if (myFlag == 1)             {                 height = "60%";                 width = "60%";             }             someString = "Height: " + height + Environment.NewLine + "Width: " + width;         }         myTimer.Stop();         File.WriteAllText("testif.txt", someString);         return myTimer.ElapsedMilliseconds;     } 

IL Code Generated By ildasm.exe

Block #1

.method public hidebysig instance int64  WithIfAndElse(int32 myFlag) cil managed {   // Code size       144 (0x90)   .maxstack  3   .locals init ([0] class [System]System.Diagnostics.Stopwatch myTimer,            [1] string someString,            [2] int32 i,            [3] string height,            [4] string width,            [5] string[] CS$0$0000)   IL_0000:  newobj     instance void [System]System.Diagnostics.Stopwatch::.ctor()   IL_0005:  stloc.0   IL_0006:  ldstr      ""   IL_000b:  stloc.1   IL_000c:  ldloc.0   IL_000d:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Start()   IL_0012:  ldc.i4.0   IL_0013:  stloc.2   IL_0014:  br.s       IL_0070   IL_0016:  ldarg.1   IL_0017:  ldc.i4.1   IL_0018:  bne.un.s   IL_0029   IL_001a:  ldstr      "60%"   IL_001f:  stloc.3   IL_0020:  ldstr      "60%"   IL_0025:  stloc.s    width   IL_0027:  br.s       IL_0036   IL_0029:  ldstr      "80%"   IL_002e:  stloc.3   IL_002f:  ldstr      "80%"   IL_0034:  stloc.s    width   IL_0036:  ldc.i4.5   IL_0037:  newarr     [mscorlib]System.String   IL_003c:  stloc.s    CS$0$0000   IL_003e:  ldloc.s    CS$0$0000   IL_0040:  ldc.i4.0   IL_0041:  ldstr      "Height: "   IL_0046:  stelem.ref   IL_0047:  ldloc.s    CS$0$0000   IL_0049:  ldc.i4.1   IL_004a:  ldloc.3   IL_004b:  stelem.ref   IL_004c:  ldloc.s    CS$0$0000   IL_004e:  ldc.i4.2   IL_004f:  call       string [mscorlib]System.Environment::get_NewLine()   IL_0054:  stelem.ref   IL_0055:  ldloc.s    CS$0$0000   IL_0057:  ldc.i4.3   IL_0058:  ldstr      "Width: "   IL_005d:  stelem.ref   IL_005e:  ldloc.s    CS$0$0000   IL_0060:  ldc.i4.4   IL_0061:  ldloc.s    width   IL_0063:  stelem.ref   IL_0064:  ldloc.s    CS$0$0000   IL_0066:  call       string [mscorlib]System.String::Concat(string[])   IL_006b:  stloc.1   IL_006c:  ldloc.2   IL_006d:  ldc.i4.1   IL_006e:  add   IL_006f:  stloc.2   IL_0070:  ldloc.2   IL_0071:  ldc.i4     0xf4240   IL_0076:  blt.s      IL_0016   IL_0078:  ldloc.0   IL_0079:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Stop()   IL_007e:  ldstr      "testifelse.txt"   IL_0083:  ldloc.1   IL_0084:  call       void [mscorlib]System.IO.File::WriteAllText(string,                                                                    string)   IL_0089:  ldloc.0   IL_008a:  callvirt   instance int64 [System]System.Diagnostics.Stopwatch::get_ElapsedMilliseconds()   IL_008f:  ret } // end of method frmResearch::WithIfAndElse 

Block #2

.method public hidebysig instance int64  WithOnlyIf(int32 myFlag) cil managed {   // Code size       142 (0x8e)   .maxstack  3   .locals init ([0] class [System]System.Diagnostics.Stopwatch myTimer,            [1] string someString,            [2] int32 i,            [3] string height,            [4] string width,            [5] string[] CS$0$0000)   IL_0000:  newobj     instance void [System]System.Diagnostics.Stopwatch::.ctor()   IL_0005:  stloc.0   IL_0006:  ldstr      ""   IL_000b:  stloc.1   IL_000c:  ldloc.0   IL_000d:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Start()   IL_0012:  ldc.i4.0   IL_0013:  stloc.2   IL_0014:  br.s       IL_006e   IL_0016:  ldstr      "80%"   IL_001b:  stloc.3   IL_001c:  ldstr      "80%"   IL_0021:  stloc.s    width   IL_0023:  ldarg.1   IL_0024:  ldc.i4.1   IL_0025:  bne.un.s   IL_0034   IL_0027:  ldstr      "60%"   IL_002c:  stloc.3   IL_002d:  ldstr      "60%"   IL_0032:  stloc.s    width   IL_0034:  ldc.i4.5   IL_0035:  newarr     [mscorlib]System.String   IL_003a:  stloc.s    CS$0$0000   IL_003c:  ldloc.s    CS$0$0000   IL_003e:  ldc.i4.0   IL_003f:  ldstr      "Height: "   IL_0044:  stelem.ref   IL_0045:  ldloc.s    CS$0$0000   IL_0047:  ldc.i4.1   IL_0048:  ldloc.3   IL_0049:  stelem.ref   IL_004a:  ldloc.s    CS$0$0000   IL_004c:  ldc.i4.2   IL_004d:  call       string [mscorlib]System.Environment::get_NewLine()   IL_0052:  stelem.ref   IL_0053:  ldloc.s    CS$0$0000   IL_0055:  ldc.i4.3   IL_0056:  ldstr      "Width: "   IL_005b:  stelem.ref   IL_005c:  ldloc.s    CS$0$0000   IL_005e:  ldc.i4.4   IL_005f:  ldloc.s    width   IL_0061:  stelem.ref   IL_0062:  ldloc.s    CS$0$0000   IL_0064:  call       string [mscorlib]System.String::Concat(string[])   IL_0069:  stloc.1   IL_006a:  ldloc.2   IL_006b:  ldc.i4.1   IL_006c:  add   IL_006d:  stloc.2   IL_006e:  ldloc.2   IL_006f:  ldc.i4     0xf4240   IL_0074:  blt.s      IL_0016   IL_0076:  ldloc.0   IL_0077:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Stop()   IL_007c:  ldstr      "testif.txt"   IL_0081:  ldloc.1   IL_0082:  call       void [mscorlib]System.IO.File::WriteAllText(string,                                                                    string)   IL_0087:  ldloc.0   IL_0088:  callvirt   instance int64 [System]System.Diagnostics.Stopwatch::get_ElapsedMilliseconds()   IL_008d:  ret } // end of method frmResearch::WithOnlyIf 

So we can say that the IF-Else block(Block #1) runs faster than the if block(Block #2) as pointed by many in this forum.

like image 358
Vamsi Avatar asked Oct 12 '11 13:10

Vamsi


People also ask

Is if better than if-else?

In general, "else if" style can be faster because in the series of ifs, every condition is checked one after the other; in an "else if" chain, once one condition is matched, the rest are bypassed.

Why is if-else better than if if?

Use two if statements if both if statement conditions could be true at the same time. In this example, both conditions can be true. You can pass and do great at the same time. Use an if/else statement if the two conditions are mutually exclusive meaning if one condition is true the other condition must be false.

Which is faster if or else?

Conclusion: If only is faster than If-Else construct. There is no difference, no "optimization" potential, between any of the alternatives at the source code level.

Does if-else affect performance?

In general it will not affect the performance but can cause unexpected behaviour. In terms of Clean Code unneserry if and if-else statements have to be removed for clarity, maintainability, better testing. One case where the performance will be reduced because of unnecessary if statements is in loops.


2 Answers

Test Results

10,000,000 iterations of Block 1

myFlag = 0:    23.8ns per iteration myFlag = 1:    23.8ns per iteration 

10,000,000 iterations of Block 2

myFlag = 0:    23.8ns per iteration myFlag = 1:    46.8ns per iteration 

Block 2 is 96% slower than Block 1. Makes sense, since Block 2 does twice the work in the pessimistic case.

i prefer either case, depending on the situation. If myFlag is rarely ever 1, then it want it to stand out as the edge case that we have to handle. If both are equally likely, i want the if-else syntax. But that's preference, not fact.


Decades ago, the intel 80286 dual pipeline would stall if a conditional jump was taken, rather than falling through to the next instruction. By the time of the Pentium that went away; the CPU pre-fetches both branch paths. But in the back of my mind i still have a twinge of fear whenever i write code that has the most common outcome in the else clause. Every time i have to remind myself that it doesn't matter anymore.


Int32 reps = 10000000;  private void Block1(int myFlag) {     String width;     String height;      Stopwatch sw = new Stopwatch();     sw.Start();     for (int i = 0; i < reps; i++)     {         if (myFlag == 1)         {             width = String.Format("{0:g}%", 60);             height = String.Format("{0:g}%", 60);         }         else         {             width = String.Format("{0:g}%", 80);             height = String.Format("{0:g}%", 80);         }     }     sw.Stop();     Double time = (Double)sw.Elapsed.Ticks / Stopwatch.Frequency * 1000000000.0 / reps;     MessageBox.Show(time.ToString() + " ns"); }  private void Block2(int myFlag) {     String width;     String height;      Stopwatch sw = new Stopwatch();     sw.Start();     for (int i = 0; i < reps; i++)     {         width = String.Format("{0:g}%", 80);         height = String.Format("{0:g}%", 80);         if (myFlag == 1)         {             width = String.Format("{0:g}%", 60);             height = String.Format("{0:g}%", 60);         }     }     sw.Stop();      Double time = (Double)sw.Elapsed.Ticks / Stopwatch.Frequency * 1000000000.0 / reps;     MessageBox.Show(time.ToString() + " ns"); } 
  • String.Format makes IF 96% slower
  • GetPercentageString(0.60) makes IF 96% slower

const    reps = 10000000;  procedure Block1(myflag: Integer); var    width, height: string;    i: Integer;    t1, t2: Int64;    time: Extended;    freq: Int64; begin    QueryPerformanceCounter(t1);    for i := 1 to reps do    begin       if myFlag = 1 then       begin          width := '60%';          height := '60%';       end       else       begin          width := '80%';          height := '80%';       end;    end;    QueryPerformanceCounter(t2);    QueryPerformanceFrequency(freq);     time := (t2-t1) / freq * 1000000000 / reps;    ShowMessage(FloatToStr(time)+ 'ns'); end;  procedure Block2(myflag: Integer); var    width, height: string;    i: Integer;    t1, t2: Int64;    time: Extended;    freq: Int64; begin    QueryPerformanceCounter(t1);    for i := 1 to reps do    begin       width := '80%';       height := '80%';       if myFlag = 1 then       begin          width := '60%';          height := '60%';       end;    end;    QueryPerformanceCounter(t2);    QueryPerformanceFrequency(freq);     time := (t2-t1) / freq * 1000000000 / reps;    ShowMessage(FloatToStr(time)+ 'ns'); end; 

Doing twice the amount of work takes roughly twice the amount of time.

Answer: IF does not perform better than IF-ELSE.


enter image description here

like image 199
Ian Boyd Avatar answered Sep 19 '22 03:09

Ian Boyd


The performance gain here is negligible to the tune I'd call this micro-micro-micro-optimization. Go for readability here unless you plan to do this a couple of million times.

Edit: (re: question in comments)

In my opinion the first one is the more readable. It explicitly shows in a ready format what the strings should be for each case. The second one omits a case, so a reviewer would have to look through other areas of the code to determine the default value. To put it into perspective, imagine 50 lines of code between the original declaration/initialization and this particular code block. If it becomes unclear in that case then that would decide it for me.

like image 23
Joel Etherton Avatar answered Sep 22 '22 03:09

Joel Etherton