There are a number of different ways to measure the execution time of a script, some of which are better than others. This page will take a look at a couple of options.
time
Moduletime.time()
This function returns the length of time in seconds that have passed since the epoch: 00:00:00 (UTC) on 1 January 1970. So calling it at the start of your programme and then again at the end of your programme will enable you to find the difference and hence the time it took for the programme to run:
import time
# Start the timer
start_time = time.time()
# Run a programme
time.sleep(1)
for n in range(1000000):
pass
# End the timer
end_time = time.time()
# Elapsed time
delta = end_time - start_time
print(
f'Start time: {start_time} seconds since the epoch',
f'End time: {end_time} seconds since the epoch',
f'Running time: {delta} s',
sep='\n'
)
## Start time: 1687653207.7965286 seconds since the epoch
## End time: 1687653208.8294632 seconds since the epoch
## Running time: 1.0329346656799316 s
Note that:
time.time()
function uses the computer’s clock time, which can be adjusted by the usertime.time_ns()
- avoids this problem by returning the number of nanoseconds since the epoch, as an integer.In other words, if you time a script that runs during a period when a leap second occurs or when the system clock is changed this method will be inaccurate. Also, the precision of this method might not be the same from one computer to the next.
time.process_time()
This option records the elapsed time of the current process, ie the system and CPU time spent running the script.
time.sleep()
function) is NOT countedtime.time()
) which means that only the difference between two calls to time.process_time()
has meaningprocess_time_ns()
can be used for more consistent precisionimport time
# Start the timer
start = time.process_time()
# Run a programme
time.sleep(1)
for n in range(1000000):
pass
# End the timer
end = time.process_time()
# Elapsed time
delta = end - start
print(f'Running time: {delta} s')
## Running time: 0.049245309999999876 s
time.perf_counter()
This is a similar function to time.process_time()
except it has more resolution and it DOES include the time elapsed due to time.sleep()
. But, like time.process_time()
, it has no reference time and so only the difference between two calls has meaning. There again exists a sister function that avoids precision loss: time.perf_counter_ns()
import time
# Start the timer
start = time.perf_counter()
# Run a programme
time.sleep(1)
for n in range(1000000):
pass
# End the timer
stop = time.perf_counter()
# Elapsed time
delta = stop - start
print(f'Running time: {delta} s')
## Running time: 1.039348770998913 s
datetime
ModuleThis is the same idea as using time.time()
except using datetime.now()
instead:
import time
from datetime import datetime
# Start the timer
start_time = datetime.now()
# Run a programme
time.sleep(1)
for n in range(1000000):
pass
# End the timer
end_time = datetime.now()
# Elapsed time
delta = end_time - start_time
print(
f'Start time: {start_time}',
f'End time: {end_time}',
f'Running time: {delta}',
sep='\n'
)
## Start time: 2023-06-26 14:06:33.198809
## End time: 2023-06-26 14:06:34.226956
## Running time: 0:00:01.028147
timeit
ModuleThis module is used for measuring the execution time of small code snippets. Your programme needs to be defined as a text string and then it can be run multiple times and averaged to give a more accurate answer. It also turns off garbage collection (the process of freeing memory when it is not used anymore) which makes the timings more consistent:
from timeit import timeit
# Define a programme in text
stmt = """
time.sleep(1)
for n in range(1000000):
pass
"""
# Choose how many times to run it
n = 10
# Run this programme the given number of times and calculate the average time
t = timeit(stmt, number=n) / n
print(f'Running time: {t} s (average of {n} repeats)')
Running time: 1.016366180499972 s (average of 10 repeats)
For the record, timeit()
uses time.perf_counter()
in the background to record the time of the script.
In order to choose the most appropriate method for your use case you need to ask yourself why you are measuring the time it took for your script to run. Are you interested in knowing how long you will have to wait for it to finish the next time you run it (ie do you care about the execution time on a human scale) or are you interested in knowing how efficient your code is (ie do you care about the execution time on a micro scale)?
time.time()
. This will give you the execution time in seconds by default and, if you decide later that you do want to know when you ran it, you’ll have the option to work this out from the seconds since the epoch value (if you recorded it!).datetime.now()
method. This will show the execution time in a more relevant h:mm:ss
format and the date and time when it was run in a more relevant YYYY-MM-DD hh:mm:ss
format.time.perf_counter()
if you want to know the real time your code takes to run (as if you were using a stopwatch)time.process_time()
if you want to know the time your computer spends on running your code. Your computer usually does lots of things at the same time so won’t spend 100% of its time on your code, hence this time.process_time()
value should theoretically always be smaller than the time.perf_counter()
value*.timeit()
for small sections of code, eg to work out which of two functions is more efficient. This is the best method for performance testing code because it can run it multiple times to reduce the variation and it turns off garbage collection to increase consistency, but it requires a bit more set up than the other options.*Here’s a demonstration to show that this is not always true:
import time
# Start the timers
start_pt = time.process_time()
start_pc = time.perf_counter()
# Run a programme
for n in range(1000000):
pass
# End the timers
stop_pt = time.process_time()
stop_pc = time.perf_counter()
# Elapsed time
delta_pt = stop_pt - start_pt
delta_pc = stop_pc - start_pc
print(
'Running time:',
f'{delta_pt} s for the process time',
f'{delta_pc} s for the performance counter',
sep='\n'
)
Running time:
0.022885440000000003 s for the process time
0.022890950998771586 s for the performance counter
Running time:
0.018469575999999998 s for the process time
0.01846678900074039 s for the performance counter
The first time I ran this the process time was the smaller of the two, but the second time the performance counter was smaller! Of course, this demonstration is not perfect because the process time is including the time used to record the start of the performance counter and the performance counter is including the time used to record the end of the process time. However, I reckon that this is enough to demonstrate that one method will not always give a lower value than the other. Also note the large variation in the length of time the code took to run: 0.023 seconds vs 0.018 seconds! The variation in the time a programme takes to run on a regular computer (with an out-of-the box operating system) is vastly more than the precision of these functions.