I'd like to know why there's a two-fold difference in execution time between these two codes

84 Views Asked by At

In computer architecture class, I learned that when the "if" statement is executed in assembly language, it involves the use of branch prediction strategies. Furthermore, it was emphasized that the operation of branch prediction incurs a significant cost.

To explore this concept further, I created the following example. I initially anticipated that the presence of the "if" statement would result in longer execution times. However, to my surprise, the code with the "if" statement actually executed faster, and the difference in execution time was nearly two-fold (1.8 seconds for the code with "if" vs. 2.5 seconds for the code without "if").

I have contemplated this matter but have been unable to pinpoint the reason for the nearly two-fold difference in execution time. I would greatly appreciate any advice or insights on aspects I may not have considered.

import time

def without_if(x):
    arr = ["Zero","One", "Two", "Three", "Four", "Five"]
    return arr[x]

num_iterations = 10000000

start_time = time.time()
for _ in range(num_iterations):
    result = without_if(5)
end_time = time.time()

print(f"Result: {result}")
print(f"Execution time without if: {end_time - start_time}")
import time

def with_if(x):
    if x == 1:
        return "One"
    elif x == 2:
        return "Two"
    elif x == 3:
        return "Three"
    elif x == 4:
        return "Four"
    elif x == 5:
        return "Five"
    else:
        return "Unknown"

num_iterations = 10000000

start_time = time.time()
for _ in range(num_iterations):
    result = with_if(5)
end_time = time.time()

print(f"Result: {result}")
print(f"Execution time with if: {end_time - start_time}")

I executed each of these codes 10 times, and in all cases, the time difference consistently remained at approximately two-fold.

I suspected that the issue might be related to the programming language, so I converted the same code to Java and executed it, but I still observed the consistent two-fold difference in execution time.

1

There are 1 best solutions below

0
Jan_B On

As mentioned in the comments you should use the timeit function to get execution time for a specific number of repetitions.

Also note that you are not really comparing the same thing! You tried comparing creating a list and accessing an element by its index to 6 if statements and retruning a string. Instead create the list of elements to acess by without_if outside of the function, because this operation is slowing without_if down:

from timeit import timeit


arr = ["Zero", "One", "Two", "Three", "Four", "Five"]
num_iterations = 10000000


def without_if(x):
    return arr[x]


def with_if(x):
    if x == 1:
        return "One"
    elif x == 2:
        return "Two"
    elif x == 3:
        return "Three"
    elif x == 4:
        return "Four"
    elif x == 5:
        return "Five"
    else:
        return "Unknown"


if __name__ == '__main__':
    print(f'Result without if {timeit(lambda: without_if(5), number=num_iterations)}')
    print(f'Result with if {timeit(lambda: with_if(5), number=num_iterations)}')

Output:

Result without if 0.9158157
Result with if 1.3290761

Maby consider this approach to even more equalize the two functions to focus on the effect of the if statement:

from timeit import timeit


arr = ["Zero", "One", "Two", "Three", "Four", "Five"]
num_iterations = 10000000


def without_if(x):
    return arr[x]


def with_if(x):
    if x < 5:
        return arr[x]


if __name__ == '__main__':
    print(f'Result without if {timeit(lambda: without_if(5), number=num_iterations)}')
    print(f'Result with if {timeit(lambda: with_if(5), number=num_iterations)}')

wich returns for me:

Result without if 0.8870418
Result with if 0.9061326

The answer to this question might interesst you. Also according to this paper:

[...] the accuracy of indirect branch prediction is no longer critical for interpreters [...]