Python decorator to time function

Simple solution: use timeit

Occasionally,  there is a need to measure how long a function runs. The simplest solution in Python would be using timeit module (note: time.time() will also give a rough sense but less accurate due to garbage collection, repetitive calls.

Timeit will use a timer with the highest-resolution on the given platform, and from Python docs: “it avoids a number of common traps for measuring execution times” – one of them is measuring only a few times.

So:

from timeit import default_timer as timer

def do_work():
    start = timer()
    # do some work
    total = timer() - start    
    print(f'Finished [do_work] in {total} secs')

 

But this is fine until you have to measure repeatedly for other methods. Then Python decorator is here to help.

better solution: use Decorator

With a little help using decorator, here it is:

import functools
from timeit import default_timer as timer

def timed(func):
    @functools.wraps(func)
    def timed_wrapper(*args, **kw):
        time_start = timer()
        result = func(*args, **kw)
        total = timer() - time_start
        print(f"---8<-------[ {func.__name__!r} ]------------------")
        print(f"Finished in {total} secs")
        return result
    return timed_wrapper

Usage:

import time

@timed
def your_function(*args, **kwargs):
    usual_code_here()

# e.g.
@timed
def concurrent_work(items):
    num_of_cpu = len(items) if len(items) < multiprocessing.cpu_count() else multiprocessing.cpu_count()
    with multiprocessing.Pool(num_of_cpu) as pool:
        result = pool.map(single_core_work,items)
    return result

@timed
def single_core_work(item):
    print(item)
    time.sleep(1000)

————–

Updates:

  1. Switch from time.time() to timeit.default_timer for better accuracy.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.