Статьи
September 25, 2023

Измеряем время исполнения программы в Python

В этом материале мы посмотрим, как рассчитать время выполнения программы, как измерить общее время, затраченное на выполнение блока кода (в секундах, миллисекундах, минутах) и научимся измерять время выполнения функций и циклов.

Будем использовать следующие способы:

  • функция time.time() – измеряет общее время, затраченное на выполнение скриптав секундах;
  • функция time.process_time() – измеряет процессорное время (CPU time) выполнения кода;
  • модуль timeit – измеряет время выполнения небольшого фрагмента кода (одну или несколько строк);
  • модуль DateTime – измеряет время выполнения в формате (часы-минуты-секунды).

Содержание

  1. Общее и процессорное время
  2. Измерение времени исполнения кода в Python
  3. Измеряем процессорное время при помощи process_time()
  4. Измерение времени исполнения при помощи модуля timeit
  5. Модуль DateTime для определения времени исполнения скрипта
  6. Заключение

Результаты измерения времени выполнения программы или её отдельных частей будет зависеть от операционной системы, версии Python и вашего понимания того, что вы подразумеваете под словом «время».

Давайте разбираться, что есть «время».

Общее и процессорное время

Есть два главных термина для измерения времени исполнения: общее время и процессорное время.

Общее время (Wall time) можно измерить с помощью секундомера. По сути, это отрезок времени от начала до конца работы программы (включая время на ожидание ресурсов).

Процессорное время (CPU time), в свою очередь, – это промежуток, в который центральный процессор был занят обработкой инструкций программы. В него не включается время, затраченное на ожидание завершения других задач (например, операций ввода/вывода) и время ожидания ресурсов.

Разница  между этими двумя типами может быть обусловлена, например, запрограммированными задержками (sleep) или ожиданием доступа системных ресурсов.

Например, если программа сообщает: «CPU time 0m0.2s, Wall time 2m4s», это означает, что она была активна в течение 2 минут и 4 секунд, но процессор компьютера потратил всего лишь 0,2 секунды на выполнение вычислений. Возможно, программа ждала, пока доступные ресурсы станут доступны

В зависимости от цели, для которой вы измеряете время выполнения программы, можно выбрать вычисление Wall time или CPU time.

Измерение времени исполнения кода в Python

Модуль time в Python предоставляет различные функции, связанные со временем, например получение текущего системного времени или приостановка исполнения кода на заданное количество секунд. Ниже показано, как использовать этот модуль для расчета общего времени исполнения программы.

  1. Импортируем модуль time. Он уже поставляется со стандартной библиотекой Python, поэтому устанавливать не надо, просто делаем import time.
  2. Сохраняем время начала работы программы. Для получения текущего времени будем использовать функцию time() – она возвращает количество в unix-time. Сохраняем его в переменной start_time.
  3. Сохраняем время окончания работы программы. И снова будем  использовать функцию time(), чтобы получить текущее время и сохранить его в переменной end_time.
  4. Вычисляем время выполнения программы. Вычитаем из end_time start_time.
import time

# получаем начальное время
st = time.time()

# основная часть
# находим сумму всех чисел до миллиона
sum_x = 0
for i in range(1000000):
    sum_x += i

# ждём 3 секунды
time.sleep(3)
print('Сумма чисел до миллиона:', sum_x)

# получаем время завершения
et = time.time()

# считаем время исполнения
elapsed_time = et - st
print('Время исполнения:', elapsed_time, 'секунд')

# Сумма чисел до миллиона: 499999500000
# Время исполнения: 3.125561475753784 секунд

Используем этот способ в следующих случаях:

  • если нужно определить время выполнения скрипта;
  • если нужно измерить время, затраченное на выполнения нескольких строк кода.

Примечание: этот способ измеряет Wall time, но не CPU time.
Если ваш скрипт ожидает каких-то ресурсов, время выполнения увеличится, потому что время ожидания будет добавлено к конечному результату.

Измерение в миллисекундах

Приведенный выше пример, даёт нам результат в секундах. Просто умножаем результат на 1000, чтобы получить миллисекунды.

# получаем время исполнения в миллисекундах
res = et - st
final_res = res * 1000
print('Время исполнения:', final_res, 'миллисекунд')

# Время исполнения: 3125.988006591797 миллисекунд

Измерение в минутах

Делим результат в изначальном примере на 60, чтобы получить конечный результат в минутах.

# получаем время исполнения в минутах
res = et - st 
final_res = res / 60
print('Время исполнения:', final_res, 'минут')

# Время исполнения: 0.05200800895690918 минут

Меняем форматирование

Можно использовать strftime() для преобразования времени в более читаемый формат, например (чч-мм-сс) часы-минуты-секунды.

import time
st = time.time()

# код задачи
sum_x = 0
for i in range(1000000):
    sum_x += i
time.sleep(3)
print('Сумма:', sum_x)

elapsed_time = time.time() - st
print('Время исполнения:', time.strftime("%H:%M:%S", time.gmtime(elapsed_time)))

# Сумма: 499999500000
# Время исполнения: 00:00:03

Измеряем процессорное время при помощи process_time()

Функция time(), которую мы использовали выше, измеряет Wall time. Для измерения CPU time можно использовать process_time(), если нам не нужно включать время ожидания ресурсов в конечный результат.

import time

# получаем время начала
st = time.process_time()

# основной код
sum_x = 0
for i in range(1000000):
    sum_x += i

# ставим задержку на 3 секунды
time.sleep(3)
print('Сумма всех чисел до миллиона:', sum_x)

# Получаем время завершения
et = time.process_time()

# Считаем процессорное время исполнения
res = et - st
print('Процессорное время исполнения:', res, 'секунд')

# Сумма всех чисел до миллиона: 499999500000
# Процессорное время исполнения: 0.234375 секунд

Примечание: программа была активна более 3 секунд, но поскольку мы рассчитываем процессорное время, как вы видите, 3 секунды задержки не были в него добавлены, потому что процессор потратил всего 0,23 секунды на выполнение вычислений для программы.

Измерение времени исполнения кода при помощи модуля timeit

Модуль timeit позволяет просто рассчитать время выполнения небольшого фрагмента кода. У него есть как вызываемый интерфейс, так и интерфейс командной строки. Модуль будет полезен в следующих случаях:

  • когда нужно определить время выполнения небольшого фрагмента кода, например, функций и цикла;
  • когда нужно измерить время, затрачиваемое между конкретными строками кода.

Функция timeit.timeit() возвращает время (в секундах), затраченное на выполнение куска кода n раз:

timeit.timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000, globals=None)

Примечание: этот способ измеряет Wall time, но не CPU time.

Вот как измерить время выполнения кода с помощью модуля timeit.

  • Создаёте экземпляр Timer с помощью функции timeit().
  • Передаёте код в параметр stmt. Время исполнения этого кода и будет измеряться.
  • Если вы хотите выполнить несколько инструкций перед измеряемым кодом, передайте их в аргумент setup (например, import).
  • Указываем, сколько раз нужно исполнить код, в параметре number (значение по умолчанию — 1 000 000).
  • Вызываем функцию timeit().

Рассчитаем время исполнения функции addition(). Выполним её пять раз, чтобы получить среднее время выполнения.

import timeit

# функция для вывода суммы всех чисел до миллиона
def addition():
    print('Сумма:', sum(range(1000000)))

# будем запускать код 5 раз
n = 5

# считаем общее время исполнения
result = timeit.timeit(stmt='addition()', globals=globals(), number=n)

# считаем среднее время исполнения
print(f"Время исполнения {result / n} секунд")|

# Сумма: 499999500000
# Сумма: 499999500000
# Сумма: 499999500000
# Сумма: 499999500000
# Сумма: 499999500000

# Время исполнения 0.03770382 секунд

Примечание: Если вы запустите «тяжёлый» код со значением number по умолчанию, он потратит много времени на выполнение. В этом случае присвойте параметру number меньшее значение.
При этом timeit отключает сборщик мусора, а многократные замеры минимизируют влияние на расчёт других исполняемых процессов, поэтому мы получим более объективный результат.

Измерение времени выполнения одной строки кода

Используем %timeit в командной строке или в jupyter notebook непосредственно перед строкой кода:

%timeit [x for x in range(1000)]

# 2.08 µs ± 223 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

Кроме того, мы можем настроить эту команду, используя различные опции, для получения более точного замера.

  • Определяем количество запусков с помощью параметра -r. Например, %timeit -r10 your_code означает выполнение строки кода 10 раз.
  • Определяем количество циклов в каждом запуске с помощью комбинации параметров -r и -n.
  • Значения параметров по умолчанию: 7 запусков, 1 миллион циклов в каждом.
%timeit -r10 -n20 [x for x in range(1000)]

# 1.4 µs ± 12.34 ns per loop (mean ± std. dev. of 10 runs, 20 loops each)

Измерение времени выполнения нескольких строк кода

Используя команду %%timeit, мы можем измерить время выполнения нескольких строк кода. Параметры команды останутся прежними. Просто заменяем одинарный процент (%) на двойной (%%) :)

%%timeit -r5 -n10

sum_x = 0
for i in range(1000000):
    sum_x += i

# 10.5 µs ± 226 ns per loop (mean ± std. dev. of 5 runs, 10 loops each)

Модуль DateTime для определения времени исполнения скрипта

Тут алгоритм такой.

  • Импортируем модуль DateTime.
  • Сохраняем время начала исполнения с помощью функции datetime.now().
  • Сохраняем время завершения исполнения той же функции, но уже после замеряемых действий.
  • Из времени окончания вычитаем время начала.
import datetime
import time

# получаем время старта
st = datetime.datetime.now()

sum_x = 0
for i in range(1000000):
    sum_x += i

# ждём 3 секунды
time.sleep(3)
print('Сумма всех чисел до миллиона:', sum_x)

# получаем время завершения
et = datetime.datetime.now()

# считаем время исполнения
elapsed_time = et - st
print('Время исполнения:', elapsed_time, 'секунд')

# Сумма всех чисел до миллиона: 499999500000
# Время исполнения: 0:00:03.115498 секунд

Примечание: Этот способ измеряет Wall time, но не CPU time.

Заключение

Итак, подытожим. Есть несколько способов узнать время выполнения кода, да и само время – штука относительная: оно бывает общим (Wall time) и процессорным (CPU time).

Для измерения времени выполнения программы в Python используются: time.time() (для вычисления Wall time), time.process_time() (для вычисления CPU time), timeit.timeit(), %timeit или %%timeit и, наконец, datetime.datetime.now() (это всё тоже Wall Time).

👉🏻Подписывайтесь на PythonTalk в Telegram 👈🏻

👨🏻‍💻Чат PythonTalk в Telegram💬

🍩 Поддержать канал 🫶

Источник: PYnative