We should somehow check the performance if we want to compare some implementations to know a faster one. It can be done to use time.time()
and get the elapsed time between end time and start time. However, Python offers a better way. It’s timeit
. This post shows you how to use timeit
.
Check the elapsed time when the specified function is called x times
Let’s see the simplest example first. We need a function to be executed. Then, pass it to timeit
.
import timeit
def func1():
return 1
print(timeit.timeit(func1))
# 0.06424164399959409
print(timeit.timeit(func1, number=100))
# 5.899999450775795e-06
The output result is in second. It took 64ms for the first call but the second call took 5 microseconds. This is because the default value of number
is 1000000. It means that the function is called the specified times.
Repeat the test specified times
We might sometimes want to repeat the test. Use timeit.repeat()
in this case.
print(timeit.repeat(func1, repeat=5, number=100))
# [5.9000003602704965e-06, 5.4989995987853035e-06, 5.500000042957254e-06, 5.499999133462552e-06, 5.500000042957254e-06]
It calls the function 100 times, saves the elapsed time, and repeats it 5 times. So it shows the 5 results.
How to pass arguments to the target function
It’s impossible to pass arguments in the way above. If the target function requires arguments, we write it differently. The function specified in timeit()
must not have any arguments. Therefore, the target function needs to be wrapped by for example lambda.
import timeit
from random import randrange
def func2(a: int, b: int):
return a + b
print(timeit.timeit(lambda: func2(randrange(100), randrange(100)), number=100))
# 0.00011679899944283534
If it’s not so simple as this example, define a function to call the target function.
def call_func2():
a = randrange(100)
b = randrange(100)
func2(a + a, a - b)
print(timeit.timeit(call_func2, number=100))
In this way, we can add as many lines as we want.
Execute a function defined in another module
We might want to test functions written in another module so that we can separate the production code and the performance check code. However, I could not find a way to import a module from the parent directory.
The directory structure is as follows.
src/timeits
├── __init__.py
├── hello_world.py
├── sub
│ └── hey.py
└── use_timeit.py
Our production code is here.
# hello_world.py
print("Hello")
def hello():
print("hello world")
if __name__ == '__main__':
print("World!")
Let’s import it by specifying setup
argument. The second argument is setup
which is executed before executing the target function. It’s initialization code.
# use_timeit.py
import timeit
timeit.timeit("", "import hello_world", number=100)
# Hello
# 1.1000010999850929e-06
This means that it import hello_world
module once and executes nothing 100 times. The following code is equivalent to the example above.
import timeit
timeit.timeit("import hello_world", number=1)
We can call hello()
function with the import.
# use_timeit.py
import timeit
timeit.timeit(f"hello_world.hello()", "import hello_world", number=1)
# Hello
# hello world
# 1.9500002963468432e-05
imeit.timeit("hello()", "from hello_world import hello", number=1)
# hello world
# 1.8299997464055195e-05
Use module in sub directory
Function defined in subdirectory can be used in this way.
import timeit
timeit.timeit("hey()", "from sub.hey import hey", number=1)
# HEY
# 1.9099999917671084e-05
But I could not find a way to import a module defined in a parent directory. Please leave a comment if you know how to do it.
Show the result in another unit
The unit is second but it might be too big for some cases. If we want another unit, we should simply convert it.
import timeit
elapsed_time_second = timeit.timeit(
f"hello_world.hello()", "import hello_world", number=1
)
elapsed_time_ms = elapsed_time_second * 1000
elapsed_time_micros = elapsed_time_ms * 1000
elapsed_time_ns = elapsed_time_micros * 1000
print(
f"{format(elapsed_time_second,'.3f')} sec, "
f"{format(elapsed_time_ms, '.3f')} ms, "
f"{format(elapsed_time_micros,'.3f')} micro sec, "
f"{format(elapsed_time_ns,'.3f')} ns"
)
# hello world
# 0.000 sec, 0.019 ms, 19.100 micro sec, 19100.000 ns
Check performance
Check the following post too. This post uses timetit to check the fastest way to access data.
Comments