Python

4 Ways to Time Python Functions

Which one should you use?

Benedict Neo
bitgrit Data Science Publication

--

Photo by Mingwei Lim on Unsplash

Have you ever wondered how long it takes for your Python code to run?

Or have you wanted to compare the performance of different approaches to solving a problem?

If so, you’ll need to know how to time your Python functions.

In this guide, we’ll explore several different methods for timing Python functions, including using the time module, the timeit module, and profiling tools.

By the end of this guide, you'll have a good understanding of how to measure the elapsed time of your Python code, and you'll be able to use the appropriate method for your specific needs.

Get the code → Deepnote

Four ways to time Python Code

1. time.perf_counter()

The time.perf_counter() function is a high-resolution timing function that uses the processor's performance counter to measure time.

It's suitable for measuring the time taken by a function and the time taken by small code blocks or individual statements.

To use this function, you can call time.perf_counter() before and after the code you want to time, subtracting the start time from the end time to get the elapsed time.

One advantage of perf_counter() is that it's based on a monotonic clock, which always increments and never goes backward. This makes it more suitable for measuring the elapsed time of a process or event.

2. time.time()

The time.time() function returns the current time in seconds since the epoch (the epoch is a predefined point in time, usually the beginning of the year 1970).

It's not as precise as perf_counter(), but it can be useful for timing longer-running functions or scripts.

One potential disadvantage of time() is that it's based on the system clock, which can be adjusted by the user or the system administrator, so the clock can go backward if the system time is changed.

3. timeit module

The timeit module provides a simple way to time the execution of small bits of Python code.

It can be used to time a single function by wrapping it in a timeit.Timer object and calling the timeit() method.

One advantage of the timeit module allows you to specify the number of times the function should be run, which can help get more accurate timing results.

4. Profiling tools

If you want to get more detailed information about the performance of your code, you can use a profiling tool such as cProfile or profile.

These tools can provide detailed statistics about the time taken by different parts of your code, the number of function calls, and the amount of memory used.

Profiling tools can be particularly useful for identifying bottlenecks in your code and optimizing the performance of your application.

Note there are still many other ways to time functions, using datetime.datetime.now(), time.clock(), time.process_time(), etc. but we’ll focus on the above four for now.

Code samples

Let’s test the methods on the following function.

1. perf_counter()

2. time.time()

3. timeit

4. cprofile

Based on the output, ncalls tells us the function was called 21891 times, the total time spent was 0.005 and the average time spent per call was 0.000 seconds.

Now that you’ve seen the code samples, you’re probably already wondering, which should you use?

Which should you use?

perf_counter() vs time()

Let’s reiterate the differences between perf_counter() and time()

  1. time.perf_counter() uses the processor's performance counter to measure time while time.time() uses the system clock. In general, perf_counter() is more precise and has a higher resolution than time(), so it's often the better choice for timing small code blocks or individual statements.
  2. time.perf_counter() is based on a monotonic clock, which means that it always increments and never goes backward. This makes it more suitable for measuring the elapsed time of a process or event. On the other hand, time.time() is based on the system clock, which can be adjusted by the user or the system administrator, so the clock can go back if the system time is changed.

So, if you want to measure the elapsed time of a process or event and you need high precision and a monotonic clock time.perf_counter() is the best choice.

On the other hand, if you need to measure the elapsed time of a longer-running script or function, and precision is not as important, time.time()may be sufficient.

timeit for small bits

You might use the timeit module when you want to quickly and easily time the execution of small bits of Python code. It's particularly useful when you want to compare the performance of different approaches to solving a problem or when you want to optimize a specific piece of code.

profile for performance

You might use profiling tools when you want to get a detailed understanding of the performance of your code. Profiling tools can provide information about the time taken by different parts of your code, the number of function calls, and the amount of memory used. This can help identify bottlenecks and optimize your code.

For example, suppose you have a large Python script that is running slowly, and you want to find out which parts of the code are taking the most time.

The output of cProfile will show you a breakdown of the time taken by each function in your script, as well as the number of times each function was called. You can use this information to identify which functions take the most time and focus your optimization efforts on those functions.

I hope that cleared some stuff up for you!

Decorator to time functions

Here’s a tip for you!

To quickly time functions that you write, you can write a decorator that uses the perf_counter() function.

Then for any function you define, you just have to include the @timeit and it will show how long it took to run that function.

Below, the timeit decorator is defined, and is added to the calculate_pi function.

The calculate_pi function approximates the value of pi using the Monte Carlo method. It generates n random points in a unit square and counts the number of points that fall inside the unit circle inscribed within the square. The value of pi is then calculated as the ratio of the number of points inside the circle to the total number of points, multiplied by 4.

At the bottom, when we call calculate_pi, it shows us it took 0.7 seconds to run!

Timing Python functions is a useful skill to have in your toolkit as a developer.

Whether you’re optimizing code for performance or simply want to understand how long it takes for your code to run, several different methods are available to help you measure the elapsed time of your Python functions.

We’ve covered four of the most common methods in this guide: using the time module, the timeit module and profiling tools. Now it's your turn to put this knowledge into practice.

Try timing some Python functions using the different methods we've discussed, and see how they compare.

And if you have any questions or need further guidance, don't hesitate to reach out for help. Happy coding!

Like this article? Here are three articles you may like:

Be sure to follow the bitgrit Data Science Publication to keep updated!

Want to discuss the latest developments in Data Science and AI with other data scientists? Join our discord server!

Follow Bitgrit below to stay updated on workshops and upcoming competitions!

Discord | Website | Twitter | LinkedIn | Instagram | Facebook | YouTube

--

--