Как померить время выполнение функции вместе с выводом на экран

Рейтинг: 0Ответов: 2Опубликовано: 24.04.2023

Есть функция, которая вызывается из какого-то цикла много раз. Она обрабатывает какую-то коллекцию (например, список) поэлементно. На самом деле это может быть и не функция, а просто цикл с какими-то вычислениями, это не принципиально. Внутри функции/цикла есть вывод на экран, который позволяет мониторить состояние обработки этой коллекции. Вывод содержит количество обработанных элементов и время их обработки. Приблизительно, это выглядит вот так:

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, да и черт с ним, сказал я себе.

Вопрос: а нельзя как-то это прилично сделать?

Ответы

▲ 3Принят
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}')
▲ 2

Я бы посоветовал использовать tqdm и не париться с самостоятельным вычислением и выводом. Он вам покажет и число прошедших и оставшихся итераций, и время выполнения, и примерное оставшееся время, и количество итераций в секунду, и ничего не нужно считать самому "вручную":

from tqdm.auto import tqdm

...
for item in tqdm(some_collection):
    ...