Как померить время выполнение функции вместе с выводом на экран
Есть функция, которая вызывается из какого-то цикла много раз. Она обрабатывает какую-то коллекцию (например, список) поэлементно. На самом деле это может быть и не функция, а просто цикл с какими-то вычислениями, это не принципиально. Внутри функции/цикла есть вывод на экран, который позволяет мониторить состояние обработки этой коллекции. Вывод содержит количество обработанных элементов и время их обработки. Приблизительно, это выглядит вот так:
end_time = 0
for i in range(len(some_collection)):
start_time = time.time()
# какие-то вычисления
end_time += time.time() - start_time
print(i, end_time, end_time / i)
Но это некорректно, так как не учитывает время выполнения самого вывода, а это медленная операция. Тогда делаем так:
end_time = 0
for i in range(len(some_collection)):
start_time = time.time()
# какие-то вычисления
print(i, end_time, end_time / i)
end_time += time.time() - start_time
Но тогда получается, что я вынужден пропускать вывод нулевой итерации (у нас же неизвестен end_time, так как он находится после вывода, да и вообще деление на ноль) и начинать выводить с первой, но нулевую.
end_time = 0
for i in range(len(some_collection)):
start_time = time.time()
# какие-то вычисления
if i !=0:
print(i, end_time, end_time / i)
end_time += time.time() - start_time
Уже изрядно костыльно получается, но и это не конец костылей, так как в таком виде мы теряем последнюю итерацию и ее время не будет учтено. Значит надо делать еще один вывод:
end_time = 0
for i in range(len(some_collection)):
start_time = time.time()
# какие-то вычисления
if i !=0:
print(i, end_time, end_time / i)
end_time += time.time() - start_time
if i == len(some_collection):
print(i+1, end_time, end_time / (i+1))
Все равно мы теряем время последнего print, да и черт с ним, сказал я себе.
Вопрос: а нельзя как-то это прилично сделать?
Ответы (2 шт):
start_time = time.perf_counter()
for i in range(len(some_collection)):
# какие-то вычисления
duration = time.perf_counter() - start_time
rate = duration / (i + 1)
print(i + 1, duration, f'{rate:.2f}')
Я бы посоветовал использовать tqdm и не париться с самостоятельным вычислением и выводом. Он вам покажет и число прошедших и оставшихся итераций, и время выполнения, и примерное оставшееся время, и количество итераций в секунду, и ничего не нужно считать самому "вручную":
from tqdm.auto import tqdm
...
for item in tqdm(some_collection):
...