#python
#python
Вопрос:
Я понимаю, что time.perf_counter() измеряет общее прошедшее время, даже если процесс в данный момент не запущен. однако time.process_time() измеряет только время фактического выполнения процесса.
Если я просто измеряю производительность функции, какая из этих двух предпочтительнее?
Поскольку меня на самом деле не интересует время, которое мой процессор тратит на другие процессы, я, естественно, подумал, что time.process_time() будет лучше (и стабильнее при разных запусках?) выбор, но имя time.perf_counter(), похоже, предполагает иное.
Пример кода
import time
from tqdm import trange
start_time_proc = time.process_time()
start_time_perf = time.perf_counter()
tmp = False
for _ in trange(10_000_000):
tmp = not tmp
elapsed_time_proc = time.process_time() - start_time_proc
elapsed_time_perf = time.perf_counter() - start_time_perf
print("process_time:", elapsed_time_proc)
print("perf_counter:", elapsed_time_perf)
Ответ №1:
Обычный способ измерения — использовать счетчик производительности и повторить измерение пару раз.
Время процесса часто не используется, и я могу легко показать вам, почему: time.sleep(1)
займет 0 секунд в зависимости от времени процесса. Каждый раз, когда процесс удаляется из планировщика, даже если это связано с тестируемым кодом, часы процесса не продвигаются.
Могу ли я предложить вам взглянуть на встроенный модуль timeit? Он также использует счетчик производительности и может обеспечить более удобный интерфейс для повторного синхронизации.
Редактировать:
Тогда и только тогда, когда ваша функция полностью привязана к процессору, не обращается к внешним ресурсам и не вызывает никаких системных вызовов вообще, process_time
является более точным и лучшим выбором.
Комментарии:
1. это зависит от того, какова цель измерения: если кто-то хочет измерить реальное прошедшее время, например, секундомер, тогда действительно вы хотите включить время ожидания и так далее — вы хотите знать, сколько времени требуется для перехода из состояния A в B. В реальных тестах производительности мы целенаправленно исключаем артефакты времени ожидания и планирования операционной системы. (а) если ваша программа не выполняет вычисления, это не влияет на время выполнения программы и (б)
sleep
время может превышать вычислительное при работе на кластерах и облачных компьютерах — программа работает только в течение доли времени, разделяя процессор с другими пользователями2. Вы полностью правы, но если ваша функция содержит что-либо, относящееся к ОС, и рассчитывает, что ОС отменит планирование процесса, ваши измерения не будут точными во времени процесса. Это будет точно для расчета процессорного времени, затрачиваемого на кластере, но если ваш вопрос «Сколько времени в среднем требуется для выполнения функции x?», время обработки не отвечает на этот вопрос.
3. Если, например, ваша функция пытается принять мьютекс или ожидает события, пока не наступит тайм-аут в 2 секунды. Какова максимальная продолжительность, которую займет эта функция? Очевидный ответ, который можно было бы ожидать, — это 2 секунды оставшаяся часть t dt (для точности планирования), в то время как во время процесса лучшим, средним и наихудшим временем будет «остаток t», хотя и с меньшим отклонением.
4. ну, в первом комментарии у вас есть точка зрения, а второй не применим (поскольку это предполагает что-то вроде «синхронизации асинхронных событий» — странный термин для использования «синхронизации» или «сравнительного анализа» здесь). Действительно, в этой настройке есть артефакты из связанных с кластером планировщиков, таких как SLURM и SGE, но определение остается в силе:
process_time
подсчитывает время, прошедшее между 2 вызовами синхронизации для того процесса, в котором процесс не былsleep()
. Конечно, ОС разные, но в Linux планирование — этоsleep
событие, осуществляемое извне в вашем процессе. Таким образом,process_time
избавляется от некоторых артефактов.5. Общее соглашение заключается в минимизации влияния артефакта планировщика на контрольные показатели путем применения «правила больших чисел» и запуска контрольной функции несколько раз и усреднения результата. Кроме того, измерение небольших разделов более надежно для тех артефактов, которые измеряют длинные разделы. Тем не менее,
process_time
уже уменьшает эти артефакты: напишите небольшой скрипт с вашей функцией, запустите 200 конкурирующих процессов, которые просто подсчитывают переменную, запустите процессы, запустите вашу функцию и время выполнения с обоими модулями. Тогда вы видите разницу.