Optimizing If-Else Statements for best performance
Do you ever have the desire to optimize your code as much as possible?
Do you have any cases where every nanosecond matters?
Do you use If statements?
This quick tip can help your code run slightly faster with no additional code.
We all know that for each command executed, there is a cost associated with it. Re-ordering your If Statements may lead to small performance gains (size of gains will depend on amount of iterations).
When using If Statements, putting your most likely case in the IF clause will yield the best performance. This is true because for each additional ElseIf clause that is added, all prior clauses must first be evaluated.
Based on my tests, given the following If Statement structure: Clause1...ClauseN-Else. The time to reach Clause1 will be fastest, followed by Clause2, etc... However, this pattern only repeats until ClauseN-1. Else will be slightly faster than ClauseN. It appears that the conditional jump from ClauseN to Else is less expensive than the jump from ClauseN to the end of the If statement, so Else is slightly less expensive than ClauseN. NOTE: See below for the case where N=1.
See the following test case and results:
When N>1:
ClassMethod Run2()
{
For i=1:1:4 {
Set time(i,"start")=$zh
For j=1:1:1000000 {
If i=1 {
set a=1
} ElseIf i=2 {
set a=1
} ElseIf i=3 {
set a=1
} Else {
set a=1
}
}
Set time(i,"end")=$zh
}
W "Time for If: ",time(1,"end")-time(1,"start")," seconds",!
W "Time for ElseIf #1: ",time(2,"end")-time(2,"start")," seconds",!
W "Time for ElseIf #2: ",time(3,"end")-time(3,"start")," seconds",!
W "Time for Else: ",time(4,"end")-time(4,"start")," seconds",!
}Time for If: .02166 seconds
Time for ElseIf #1: .026443 seconds
Time for ElseIf #2: .035915 seconds
Time for Else: .032695 seconds
When N=1:
ClassMethod Run()
{
For i=1:1:2 {
Set time(i,"start")=$zh
For j=1:1:1000000 {
If i=1 {
set a=1
} Else {
set a=1
}
}
Set time(i,"end")=$zh
}
W "Time for If: ",time(1,"end")-time(1,"start")," seconds",!
W "Time for Else: ",time(2,"end")-time(2,"start")," seconds",!
}Time for If: .02168 seconds
Time for Else: .015388 seconds
Based on these results, In the case where you have IF-Else, you should put your most common case in the Else Block. In the case where you use If-ElseIf-Else, you should put your most common case in the If Block.
As you can see, these numbers are relatively small compared to the 1 million iterations. However, if you are ever writing code that loops millions of times, reordering your If Statements can save you some time.
Comments
Interesting article.
Note that comparison with 1 would always be the fastest regardless of where it is:
Here's your code on my PC:
Time for If: .037652 seconds
Time for ElseIf #1: .045029 seconds
Time for ElseIf #2: .057766 seconds
Time for Else: .053267 secondsAnd here's a modified code with comparison to 1 third:
ClassMethod Run3()
{
For i=1:1:4 {
Set time(i,"start")=$zh
For j=1:1:1000000 {
If i=3 {
set a=1
} ElseIf i=2 {
set a=1
} ElseIf i=1 {
set a=1
} Else {
set a=1
}
}
Set time(i,"end")=$zh
}
W "Time for If: ",time(1,"end")-time(1,"start")," seconds",!
W "Time for ElseIf #1: ",time(2,"end")-time(2,"start")," seconds",!
W "Time for ElseIf #2: ",time(3,"end")-time(3,"start")," seconds",!
W "Time for Else: ",time(4,"end")-time(4,"start")," seconds",!
}Running this code yields these results:
Time for If: .109513 seconds
Time for ElseIf #1: .048419 seconds
Time for ElseIf #2: .029746 seconds
Time for Else: .059306 secondsRegardless of where comparison to 1 happens it would be the fastest one.
I have (2019.1.1CE) this is not confirmed:
<FONT COLOR="#0000ff">f </FONT><FONT COLOR="#800000">i</FONT><FONT COLOR="#000000">=1:1:4 </FONT><FONT COLOR="#800080">{
</FONT><FONT COLOR="#0000ff">s </FONT><FONT COLOR="#800000">time</FONT><FONT COLOR="#000000">(</FONT><FONT COLOR="#800000">i</FONT><FONT COLOR="#000000">,</FONT><FONT COLOR="#008000">"start"</FONT><FONT COLOR="#000000">)=</FONT><FONT COLOR="#0000ff">$zh
f </FONT><FONT COLOR="#800000">j</FONT><FONT COLOR="#000000">=1:1:1e6 </FONT><FONT COLOR="#800080">{
</FONT><FONT COLOR="#0000ff">i </FONT><FONT COLOR="#800000">i</FONT><FONT COLOR="#000000">=2 </FONT><FONT COLOR="#800080">{
</FONT><FONT COLOR="#0000ff">s </FONT><FONT COLOR="#800000">a</FONT><FONT COLOR="#000000">=2
</FONT><FONT COLOR="#800080">} </FONT><FONT COLOR="#0000ff">ElseIf </FONT><FONT COLOR="#800000">i</FONT><FONT COLOR="#000000">=3 </FONT><FONT COLOR="#800080">{
</FONT><FONT COLOR="#0000ff">s </FONT><FONT COLOR="#800000">a</FONT><FONT COLOR="#000000">=3
</FONT><FONT COLOR="#800080">} </FONT><FONT COLOR="#0000ff">ElseIf </FONT><FONT COLOR="#800000">i</FONT><FONT COLOR="#000000">=1 </FONT><FONT COLOR="#800080">{
</FONT><FONT COLOR="#0000ff">s </FONT><FONT COLOR="#800000">a</FONT><FONT COLOR="#000000">=1
</FONT><FONT COLOR="#800080">} </FONT><FONT COLOR="#0000ff">Else </FONT><FONT COLOR="#800080">{
</FONT><FONT COLOR="#0000ff">s </FONT><FONT COLOR="#800000">a</FONT><FONT COLOR="#000000">=0
</FONT><FONT COLOR="#800080">}
}
</FONT><FONT COLOR="#0000ff">s </FONT><FONT COLOR="#800000">time</FONT><FONT COLOR="#000000">(</FONT><FONT COLOR="#800000">i</FONT><FONT COLOR="#000000">,</FONT><FONT COLOR="#008000">"end"</FONT><FONT COLOR="#000000">)=</FONT><FONT COLOR="#0000ff">$zh
</FONT><FONT COLOR="#800080">}
</FONT><FONT COLOR="#0000ff">w </FONT><FONT COLOR="#008000">"Time for If (i=2): "</FONT><FONT COLOR="#000000">,</FONT><FONT COLOR="#800000">time</FONT><FONT COLOR="#000000">(1,</FONT><FONT COLOR="#008000">"end"</FONT><FONT COLOR="#000000">)-</FONT><FONT COLOR="#800000">time</FONT><FONT COLOR="#000000">(1,</FONT><FONT COLOR="#008000">"start"</FONT><FONT COLOR="#000000">),</FONT><FONT COLOR="#008000">" seconds"</FONT><FONT COLOR="#000000">,!,
</FONT><FONT COLOR="#008000">"Time for ElseIf #1 (i=3): "</FONT><FONT COLOR="#000000">,</FONT><FONT COLOR="#800000">time</FONT><FONT COLOR="#000000">(2,</FONT><FONT COLOR="#008000">"end"</FONT><FONT COLOR="#000000">)-</FONT><FONT COLOR="#800000">time</FONT><FONT COLOR="#000000">(2,</FONT><FONT COLOR="#008000">"start"</FONT><FONT COLOR="#000000">),</FONT><FONT COLOR="#008000">" seconds"</FONT><FONT COLOR="#000000">,!,
</FONT><FONT COLOR="#008000">"Time for ElseIf #2 (i=1): "</FONT><FONT COLOR="#000000">,</FONT><FONT COLOR="#800000">time</FONT><FONT COLOR="#000000">(3,</FONT><FONT COLOR="#008000">"end"</FONT><FONT COLOR="#000000">)-</FONT><FONT COLOR="#800000">time</FONT><FONT COLOR="#000000">(3,</FONT><FONT COLOR="#008000">"start"</FONT><FONT COLOR="#000000">),</FONT><FONT COLOR="#008000">" seconds"</FONT><FONT COLOR="#000000">,!,
</FONT><FONT COLOR="#008000">"Time for Else (i=4): "</FONT><FONT COLOR="#000000">,</FONT><FONT COLOR="#800000">time</FONT><FONT COLOR="#000000">(4,</FONT><FONT COLOR="#008000">"end"</FONT><FONT COLOR="#000000">)-</FONT><FONT COLOR="#800000">time</FONT><FONT COLOR="#000000">(4,</FONT><FONT COLOR="#008000">"start"</FONT><FONT COLOR="#000000">),</FONT><FONT COLOR="#008000">" seconds"</FONT><FONT COLOR="#000000">,!</FONT>
Time for If (i=2): .109283 seconds
Time for ElseIf #1 (i=3): .060785 seconds
Time for ElseIf #2 (i=1): .08026 seconds
Time for Else (i=4): .109974 seconds
Try with larger numbers. With the smaller numbers, there will be slight variations which can flip the order.
With 1e9:
Time for If: 28.111261 seconds
Time for ElseIf #1: 38.782421 seconds
Time for ElseIf #2: 49.21395 seconds
Time for Else: 48.58113 seconds
Hi Peter.
Ok.
<FONT COLOR="#0000ff">w </FONT><FONT COLOR="#008000">"Time for If (i=2): "</FONT><FONT COLOR="#000000">,</FONT><FONT COLOR="#800000">time</FONT><FONT COLOR="#000000">(2,</FONT><FONT COLOR="#008000">"end"</FONT><FONT COLOR="#000000">)-</FONT><FONT COLOR="#800000">time</FONT><FONT COLOR="#000000">(2,</FONT><FONT COLOR="#008000">"start"</FONT><FONT COLOR="#000000">),</FONT><FONT COLOR="#008000">" seconds"</FONT><FONT COLOR="#000000">,!, </FONT><FONT COLOR="#008000">"Time for ElseIf #1 (i=3): "</FONT><FONT COLOR="#000000">,</FONT><FONT COLOR="#800000">time</FONT><FONT COLOR="#000000">(3,</FONT><FONT COLOR="#008000">"end"</FONT><FONT COLOR="#000000">)-</FONT><FONT COLOR="#800000">time</FONT><FONT COLOR="#000000">(3,</FONT><FONT COLOR="#008000">"start"</FONT><FONT COLOR="#000000">),</FONT><FONT COLOR="#008000">" seconds"</FONT><FONT COLOR="#000000">,!, </FONT><FONT COLOR="#008000">"Time for ElseIf #2 (i=1): "</FONT><FONT COLOR="#000000">,</FONT><FONT COLOR="#800000">time</FONT><FONT COLOR="#000000">(1,</FONT><FONT COLOR="#008000">"end"</FONT><FONT COLOR="#000000">)-</FONT><FONT COLOR="#800000">time</FONT><FONT COLOR="#000000">(1,</FONT><FONT COLOR="#008000">"start"</FONT><FONT COLOR="#000000">),</FONT><FONT COLOR="#008000">" seconds"</FONT><FONT COLOR="#000000">,!, </FONT><FONT COLOR="#008000">"Time for Else (i=4): "</FONT><FONT COLOR="#000000">,</FONT><FONT COLOR="#800000">time</FONT><FONT COLOR="#000000">(4,</FONT><FONT COLOR="#008000">"end"</FONT><FONT COLOR="#000000">)-</FONT><FONT COLOR="#800000">time</FONT><FONT COLOR="#000000">(4,</FONT><FONT COLOR="#008000">"start"</FONT><FONT COLOR="#000000">),</FONT><FONT COLOR="#008000">" seconds"</FONT><FONT COLOR="#000000">,!!</FONT>1e6 Time for If (i=2): .030974 seconds Time for ElseIf #1 (i=3): .045126 seconds Time for ElseIf #2 (i=1): .07144 seconds Time for Else (i=4): .087353 seconds
1e9 Time for If (i=2): 28.59286 seconds Time for ElseIf #1 (i=3): 43.044261 seconds Time for ElseIf #2 (i=1): 82.277535 seconds Time for Else (i=4): 69.212718 seconds
Also for your test, the same with my note for Eduard - the output is hardcoded, so the first output line is for i=1, the second is for i=2, the third for i=3, the last for i=4
Hi Eduard,
Please note that the output is hardcoded, so your output for "Time for ElseIf #2" is actually for your If statement
And more food for thought:
Class dc.test [ Abstract ]
{
/// d ##class(dc.test).test()
ClassMethod test(N As %Integer = 10)
{
d ..Run1(N),..Run2(N),..Run3(N),..Run4(N)
}
ClassMethod Run1(N As %Integer)
{
f i=1:1:4 {
s time(i,"start")=$zh
f j=1:1:N {
i i=2 {
s a=20
} ElseIf i=3 {
s a=30
} ElseIf i=1 {
s a=10
} Else {
s a=-4
}
}
s time(i,"end")=$zh
}
w "If i=2: ",?12,time(2,"end")-time(2,"start")," seconds",!,
"ElseIf i=3: ",?12,time(3,"end")-time(3,"start")," seconds",!,
"ElseIf i=1: ",?12,time(1,"end")-time(1,"start")," seconds",!,
"Else: ",?12,time(4,"end")-time(4,"start")," seconds",!!
}
ClassMethod Run2(N As %Integer)
{
f i=2,3,1,4 {
s time(i,"start")=$zh
f j=1:1:N s a=$case(i,1:10,2:20,3:30,:-4)
s time(i,"end")=$zh
}
w "i=1: ",time(1,"end")-time(1,"start")," seconds",!,
"i=2: ",time(2,"end")-time(2,"start")," seconds",!,
"i=3: ",time(3,"end")-time(3,"start")," seconds",!,
"i=4: ",time(4,"end")-time(4,"start")," seconds",!!
}
ClassMethod Run3(N As %Integer)
{
f i=1,2,3,4 {
s time(i,"start")=$zh
f j=1:1:N s a=$case(i,2:20,3:30,1:10,:-4)
s time(i,"end")=$zh
}
w "i=1: ",time(1,"end")-time(1,"start")," seconds",!,
"i=2: ",time(2,"end")-time(2,"start")," seconds",!,
"i=3: ",time(3,"end")-time(3,"start")," seconds",!,
"i=4: ",time(4,"end")-time(4,"start")," seconds",!!
}
ClassMethod Run4(N As %Integer) [ ProcedureBlock = 0 ]
{
n i,time,j,a
f i=2,3,1,4 {
s time(i,"start")=$zh
f j=1:1:N d $case(i,1:a1,2:a2,3:a3,:a4)
s time(i,"end")=$zh
}
w "i=1: ",time(1,"end")-time(1,"start")," seconds",!,
"i=2: ",time(2,"end")-time(2,"start")," seconds",!,
"i=3: ",time(3,"end")-time(3,"start")," seconds",!,
"i=4: ",time(4,"end")-time(4,"start")," seconds",!!
q
a1 s a=10 q
a2 s a=20 q
a3 s a=30 q
a4 s a=-4 q
}
}
USER>d ##class(dc.test).test(1000000)
If i=2: .027962 seconds
ElseIf i=3: .043612 seconds
ElseIf i=1: .073138 seconds
Else: .068023 seconds
i=1: .035705 seconds
i=2: .035941 seconds
i=3: .03498 seconds
i=4: .033288 seconds
i=1: .078231 seconds
i=2: .052477 seconds
i=3: .066045 seconds
i=4: .07372 seconds
i=1: .051371 seconds
i=2: .052017 seconds
i=3: .050972 seconds
i=4: .052397 seconds
USER>d ##class(dc.test).test(1e6)
If i=2: .060933 seconds
ElseIf i=3: .071999 seconds
ElseIf i=1: .094509 seconds
Else: .096684 seconds
i=1: .058554 seconds
i=2: .058182 seconds
i=3: .059299 seconds
i=4: .054863 seconds
i=1: .09973 seconds
i=2: .074734 seconds
i=3: .087673 seconds
i=4: .097123 seconds
i=1: .082372 seconds
i=2: .084538 seconds
i=3: .081647 seconds
i=4: .079353 seconds