Функции monotonic(), perf_counter() и process_time()

Курс по стандартной библиотеке: https://stepik.org/a/259466?utm_source=proproprogs

Смотреть материал на YouTube | RuTube

Мы с вами продолжаем знакомство с функциями модуля time() и следующей будет функция monotonic(). Для чего она предназначена? Если вспомнить прошлое занятие, то там функция time() выдавала время, привязанное к системным часам устройства. С одной стороны это хорошо, т.к. можно определять реальное текущее время, но с другой стороны имеем некоторую уязвимость при измерении промежутков времени выполнения функций или фрагментов кода программ. Для этих целей лучше подходит функция monotonic(), которая измеряет временные интервалы независимо от изменений системных настроек или сбоев.

Вот основные характеристики работы этой функции:

  • Монотонность. Время, возвращаемое функцией monotonic(), строго возрастает с течением физического времени и не подвержено влиянию установки новых значений системных часов.
  • Абсолютное время не имеет значения. Функция monotonic() не выдает абсолютное значение времени (суток или даты), а лишь возвращает абстрактное относительное время, подходящее для измерения длительностей промежутков времени.
  • Использование в профилировании и мониторинге. Поскольку данная функция гарантирует увеличение показаний времени, она идеальна для анализа производительности и измерения длительности конкретных участков кода.
  • Независимость от платформы. Реализация функции monotonic() основана на низкоуровневых источниках времени операционной системы, обеспечивающих наибольшую точность и стабильность независимо от платформы (Windows, Linux, macOS и др.).

Воспользоваться этой функцией можно следующим образом:

t = time.monotonic()
print(t)  # 57446.875

Обратите внимание, что само по себе значение функции monotonic() никак не интерпретируется. Это просто метка времени и все. Но если в программе ее вызвать дважды:

start = time.monotonic()
time.sleep(0.5)  # задержка на 500 мс
end = time.monotonic()
print(end-start)  # 0.5

то можно замерять временные интервалы. Собственно, это ее основное предназначение.

Функция perf_counter()

Следующая функция perf_counter() работает по аналогии с функцией monotonic(), но предназначена для высокоточного измерения коротких интервалов времени. Эта функция возвращает наиболее точную доступную меру времени, зависящую от характеристик текущей ОС и оборудования.

Давайте в качестве примера повторим фрагмент предыдущего кода, но с использованием функции perf_counter():

start = time.perf_counter()
time.sleep(0.5)
end = time.perf_counter()
print(end-start)  # 0.5001650999984122

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

В чем же разница между этими двумя функциями? Вот основные особенности их работы:

  • Прикладное назначение.

    - perf_counter() используется для максимально точного измерения коротких временных интервалов.

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

  • Источник времени.

    - perf_counter() выбирает наилучший доступный источник времени для достижения максимальной точности на данном оборудовании и операционной системе. Это может быть внутренняя частота процессора или другое устройство высокого разрешения.

    - monotonic(), в свою очередь, базируется на низком уровне операционной системы, гарантируя надежность и отсутствие зависимости от изменений системных часов, но точность может уступать perf_counter().

  • Область применения.

    - perf_counter() отлично подходит для замера кратковременных интервалов, где важна высокая точность, например, при сравнении производительности алгоритмов или теста скорости отдельных фрагментов кода.

    - monotonic() же чаще используется для задач, где важна уверенность в строгом увеличении временных меток, например, для мониторинга прогресса выполнения длительной задачи или расчета таймаутов в системах реального времени.

Функция process_time()

Следующая функция process_time() из модуля time предоставляет специальный вид временной метрики, который называется процессорным временем. Процессорное время – это сумма времени, которое реально провел процесс в активном состоянии, исполняя команды на центральном процессоре. Оно учитывает как время, потраченное на выполнение инструкций ядра операционной системы (kernel mode), так и на пользовательском уровне (user mode).

Основное назначение функции – предоставление точного показателя загруженности процессора отдельным процессом. Именно поэтому она хорошо подходит для измерения реальных затрат ресурса процессора на выполнение определенного участка кода или отдельной задачи.

Для лучшего понимания работы этой функции рассмотрим следующий пример:

start_pr = time.process_time()
start_counter = time.perf_counter()
sum(i * i for i in range(1000000))  # искусственная нагрузка на процессор
time.sleep(0.2)
end_counter = time.perf_counter()
end_pr = time.process_time()
 
processor_time_used = end_pr - start_pr
total_time = end_counter - start_counter
print(f"Процессорное время: {processor_time_used:.6f} секунд")
print(f"Общее время: {total_time:.6f} секунд")

После выполнения программы, в консоли увидим строчки:

Процессорное время: 0.046875 секунд
Общее время: 0.247652 секунд

Как видите, функция process_time() измерила непосредственную нагрузку на процессор без учета его простоя в 200 мс. Тогда как функция perf_counter() измерила общее время выполнения фрагмента программы.

Таким образом, функция process_time() является удобным инструментом для анализа загрузки процессора при выполнении приложения. Она предоставляет объективные данные о расходе процессорного времени и помогает выявлять участки кода, нуждающиеся в улучшении производительности.

Курс по стандартной библиотеке: https://stepik.org/a/259466?utm_source=proproprogs

Видео по теме