Question

How to Measure Elapsed Time in Python

pythonperformancemeasuretimeit

Question

I want to measure how long a function takes to execute in Python. I tried using timeit, but it did not work as expected:

import timeit

start = timeit.timeit()
print("hello")
end = timeit.timeit()
print(end - start)

How can I correctly measure elapsed time in Python, and when should I use timeit versus other timing tools?

Short Answer

By the end of this page, you will understand how to measure elapsed time in Python correctly, why timeit.timeit() is not used like a stopwatch, and when to use time.perf_counter(), time.time(), or timeit for benchmarking code.

Concept

Python has different tools for different kinds of timing.

If you want to measure how much real time passes between two points in your code, use a clock function such as:

  • time.perf_counter() — best general choice for measuring short durations
  • time.time() — current wall-clock time, less ideal for precise benchmarking

If you want to benchmark a small piece of code repeatedly to estimate its performance, use timeit.

Your original code does not work because timeit.timeit() is not a timer start/stop function. Instead, it runs a statement many times and returns the total execution time. It is a benchmarking tool, not a stopwatch.

Why this matters

Measuring execution time is useful when you want to:

  • compare two implementations
  • detect slow parts of a program
  • verify performance improvements
  • monitor expensive operations like API calls, file processing, or loops

Using the wrong timing tool can give misleading results. For example:

  • time.time() can be affected by system clock changes
  • timeit adds its own structure for repeated measurement
  • very short operations need a high-resolution timer like time.perf_counter()

Mental Model

Think of Python timing tools like different kinds of clocks:

  • time.perf_counter() is a stopwatch — start it, stop it, and measure elapsed time.
  • time.time() is a wall clock — it tells you the current time.
  • timeit is a lab testing machine — it runs your code many times under controlled conditions to help you benchmark it.

So if you want to know, "How long did this one function call take?" use the stopwatch.

If you want to know, "Which of these two snippets is usually faster?" use the lab testing machine.

Take Quiz

Syntax and Examples

The most common way to measure elapsed time in Python is with time.perf_counter().

import time

start = time.perf_counter()
print("hello")
end = time.perf_counter()

print(end - start)

This records the time before and after the code runs, then subtracts the two values.

Measuring a function

import time


def greet():
    print("hello")

start = time.perf_counter()
greet()
end = time.perf_counter()

elapsed = end - start
print(f"Elapsed time: {elapsed:.6f} seconds")

Using timeit correctly

timeit is for benchmarking code by running it many times.

import timeit

elapsed = timeit.timeit('print("hello")', number=1)
print(f"Elapsed time: {elapsed:.6f} seconds")

Usually, timeit is more useful for small code snippets that need repeated measurement:

import timeit

elapsed = timeit.timeit('sum(range(100))', number=10000)
print(f"Total time: {elapsed:.6f} seconds")

This runs sum(range(100)) 10,000 times and returns the total time.

Better timeit example with a callable

import timeit


def work():
    return sum(range(100))

elapsed = timeit.timeit(work, number=10000)
print(f"Total time: {elapsed:.6f} seconds")

This is often cleaner and safer than passing a string.

Step by Step Execution

Consider this example:

import time


def slow_task():
    total = 0
    for i in range(5):
        total += i
    return total

start = time.perf_counter()
result = slow_task()
end = time.perf_counter()

print(result)
print(f"Elapsed: {end - start:.6f} seconds")

Step by step

  1. import time

    • Loads Python's time-related functions.
  2. def slow_task():

    • Defines a function named slow_task.
  3. total = 0

    • Creates a variable to store a running sum.
  4. for i in range(5):

    • Loops through 0, 1, 2, 3, 4.
  5. total += i

    • Adds each number to total.
  6. return total

    • Returns the final sum, which is 10.
  7. start = time.perf_counter()

    • Records the current high-resolution timer value before the function runs.
  8. result = slow_task()

    • Executes the function.
  9. end = time.perf_counter()

    • Records the timer value after the function finishes.
  10. end - start

  • Calculates how much time passed during the function call.

Important detail

The values returned by time.perf_counter() are not meant to be interpreted as calendar time. They are only useful for measuring differences:

elapsed = end - start

Real World Use Cases

Measuring elapsed time is common in real programs.

API requests

import time
import requests

start = time.perf_counter()
response = requests.get("https://example.com")
end = time.perf_counter()

print(f"Request took {end - start:.3f} seconds")

File processing

import time

start = time.perf_counter()
with open("data.txt") as f:
    data = f.read()
end = time.perf_counter()

print(f"Read completed in {end - start:.6f} seconds")

Comparing implementations

import timeit

list_time = timeit.timeit(lambda: [x * 2 for x in range(1000)], number=1000)
map_time = timeit.timeit(lambda: list(map(lambda x: x * 2, range(1000))), number=1000)

print(list_time)
print(map_time)

Monitoring slow functions

import time


def process_data():
    return sum(range(1_000_000))

start = time.perf_counter()
process_data()
end = time.perf_counter()

print(f"process_data took {end - start:.4f} seconds")
Take Quiz

Real Codebase Usage

In real projects, developers usually use timing in a few standard ways.

1. Quick profiling around a block of code

import time

start = time.perf_counter()
# code to measure
result = sum(range(100000))
elapsed = time.perf_counter() - start
print(f"Took {elapsed:.6f}s")

This is common during debugging and optimization.

2. Timing inside helper functions

import time


def timed_call(func, *args, **kwargs):
    start = time.perf_counter()
    result = func(*args, **kwargs)
    elapsed = time.perf_counter() - start
    return result, elapsed

This pattern helps reuse timing logic.

3. Logging slow operations

import time
import logging

logging.basicConfig(level=logging.INFO)

start = time.perf_counter()
value = sum(range(500000))
elapsed = time.perf_counter() - start

if elapsed > 0.01:
    logging.info("Slow operation: %.6fs", elapsed)

4. Benchmarking implementation choices

Developers use timeit when comparing tiny code snippets because one run may be too noisy.

import timeit

result = timeit.timeit(lambda: sum(range(100)), number=10000)
print(result)

5. Guarding performance-sensitive paths

Codebases sometimes measure expensive work such as:

  • database queries
  • HTTP requests
  • loops over large datasets
  • serialization and parsing
  • image or file processing

For serious profiling of a whole application, developers often move beyond manual timing and use profilers such as cProfile.

Common Mistakes

Here are common beginner mistakes when measuring time in Python.

Mistake 1: Using timeit.timeit() like a stopwatch

Broken code:

import timeit

start = timeit.timeit()
print("hello")
end = timeit.timeit()
print(end - start)

Why it is wrong:

  • timeit.timeit() runs code and returns how long that benchmark took.
  • It does not return a "current timestamp" for start and end.

Use this instead:

import time

start = time.perf_counter()
print("hello")
end = time.perf_counter()
print(end - start)

Mistake 2: Timing code that is too small only once

import time

start = time.perf_counter()
sum(range(10))
end = time.perf_counter()
print(end - start)

This may be noisy because the code runs extremely fast.

Better approach:

import timeit

print(timeit.timeit(lambda: sum(range(10)), number=10000))

Mistake 3: Using time.time() for precise benchmarking

time.time() works, but time.perf_counter() is usually better for measuring durations.

Less ideal:

import time

start = time.time()
sum(range(100000))
end = time.time()
print(end - start)

Preferred:

import time

start = time.perf_counter()
sum(range(100000))
end = time.perf_counter()
print(end - start)

Mistake 4: Including unrelated work in the measurement

import time

start = time.perf_counter()
print("starting")
sum(range(100000))
print("done")
end = time.perf_counter()

The print() calls affect the timing.

If you only care about sum(range(100000)), measure only that part.

Mistake 5: Forgetting repeated runs vary

Timing can change because of:

  • system load
  • background processes
  • caching
  • interpreter warm-up

That is why timeit often gives more reliable comparisons for tiny code.

Comparisons

ToolBest forReturnsGood for precise elapsed time?Notes
time.perf_counter()Measuring duration between two pointsHigh-resolution timer valueYesBest general choice for elapsed time
time.time()Current wall-clock timeUnix timestamp-like valueSometimesLess suitable for benchmarking
timeit.timeit()Benchmarking code snippets repeatedlyTotal execution timeYes, but for repeated benchmarksNot a start/stop stopwatch
cProfileProfiling full programsFunction-level statsNot directlyBetter for finding slow functions

time.perf_counter() vs timeit

Featuretime.perf_counter()timeit
Start/stop around codeYesNo
Runs code repeatedly automaticallyNoYes
Best for one function call or blockYesSometimes
Best for comparing tiny snippetsNot idealYes
Easy to read for beginnersYesYes

Rule of thumb

  • Use time.perf_counter() for elapsed time in normal code.
  • Use timeit for benchmarking small snippets repeatedly.
Take Quiz

Cheat Sheet

import time

start = time.perf_counter()
# code here
end = time.perf_counter()

elapsed = end - start
print(elapsed)

Best choices

  • Measure elapsed time: time.perf_counter()
  • Get current clock time: time.time()
  • Benchmark repeated runs: timeit.timeit()

timeit examples

import timeit

timeit.timeit('sum(range(100))', number=10000)
import timeit

timeit.timeit(lambda: sum(range(100)), number=10000)

Key rules

  • Do not use timeit.timeit() as start and end timestamps.
  • For short code, prefer repeated timing with timeit.
  • For normal elapsed duration, prefer time.perf_counter().
  • Subtract end minus start:
elapsed = end - start

Common edge case

Very fast code can produce noisy one-run results. Use many repetitions with timeit.

Formatting output

print(f"Elapsed: {elapsed:.6f} seconds")

FAQ

Should I use timeit or time.perf_counter()?

Use time.perf_counter() when you want to measure elapsed time around a block of code. Use timeit when you want to benchmark a small snippet by running it many times.

Why does timeit.timeit() not work as a start and end timer?

Because it does not return the current time. It executes code repeatedly and returns how long the benchmark took.

Is time.time() good enough for measuring execution time?

Sometimes, yes. But time.perf_counter() is usually the better choice for measuring durations because it has higher resolution and is intended for timing intervals.

How do I measure the runtime of a function in Python?

Wrap the function call with time.perf_counter() before and after, then subtract.

Why do my timing results change between runs?

Execution time can vary because of system load, background tasks, caching, and other environmental factors.

Can I use timeit with a function instead of a string?

Yes. Passing a callable like a function or lambda is often cleaner and safer.

What if I want to profile my whole Python program?

Use a profiler such as cProfile if you need function-level performance details across a larger application.

Take Quiz

Mini Project

Description

Build a small Python utility that measures how long different functions take to run. This demonstrates the practical difference between timing a single function call with time.perf_counter() and benchmarking repeated work more systematically.

Goal

Create a reusable timing helper and use it to measure two example functions.

Requirements

  • Write a function that accepts another function and measures its elapsed time.
  • Create two sample functions to test, such as one using a loop and one using sum().
  • Print both the function result and the elapsed time.
  • Use time.perf_counter() for the timing.
  • Keep the script runnable as a single Python file.
Take Quiz

Keep learning

Related questions

View more