Попытка использовать timeit.timeit

Я хотел бы измерить время работы для двух кодов, я попытался найти документацию по python для timeit, но я действительно не понял. Может ли кто-нибудь объяснить в словаре более начального уровня?


person user65165    schedule 21.09.2013    source источник
comment
См. также: cProfile   -  person ninMonkey    schedule 21.09.2013


Ответы (3)


Примечание. Скопировано в Как использовать модуль timeit.

Открою вам секрет: лучше всего использовать timeit в командной строке.

В командной строке timeit выполняет надлежащий статистический анализ: он сообщает, сколько времени занял самый короткий запуск. Это хорошо, потому что все ошибки во времени положительны. Таким образом, самое короткое время имеет наименьшую ошибку. Невозможно получить отрицательную ошибку, потому что компьютер никогда не сможет вычислить быстрее, чем он может вычислить!

Итак, интерфейс командной строки:

%~> python -m timeit "1 + 2"
10000000 loops, best of 3: 0.0468 usec per loop

Это довольно просто, а?

Вы можете настроить вещи:

%~> python -m timeit -s "x = range(10000)" "sum(x)"
1000 loops, best of 3: 543 usec per loop

что тоже полезно!

Если вам нужно несколько строк, вы можете либо использовать автоматическое продолжение оболочки, либо использовать отдельные аргументы:

%~> python -m timeit -s "x = range(10000)" -s "y = range(100)" "sum(x)" "min(y)"
1000 loops, best of 3: 554 usec per loop

Это дает настройку

x = range(1000)
y = range(100)

и время

sum(x)
min(y)

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

 SETUP="

 ... # lots of stuff

 "

 echo Minmod arr1
 python -m timeit -s "$SETUP" "Minmod(arr1)"

 echo pure_minmod arr1
 python -m timeit -s "$SETUP" "pure_minmod(arr1)"

 echo better_minmod arr1
 python -m timeit -s "$SETUP" "better_minmod(arr1)"

 ... etc

Это может занять немного больше времени из-за множественных инициализаций, но обычно это не имеет большого значения.


Но что, если вы хотите использовать timeit внутри своего модуля?

Ну, простой способ сделать это:

def function(...):
    ...

timeit.Timer(function).timeit(number=NUMBER)

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

Чтобы получить хороший анализ, используйте .repeat и возьмите этот минимум:

min(timeit.Timer(function).repeat(repeat=REPEATS, number=NUMBER))

Обычно вы должны комбинировать это с functools.partial вместо lambda: ..., чтобы снизить накладные расходы. Таким образом, у вас может быть что-то вроде:

from functools import partial

def to_time(items):
    ...

test_items = [1, 2, 3] * 100
times = timeit.Timer(partial(to_time, test_items)).repeat(3, 1000)

# Divide by the number of repeats
time_taken = min(times) / 1000

Вы также можете сделать:

timeit.timeit("...", setup="from __main__ import ...", number=NUMBER)

что дало бы вам что-то близкое к интерфейсу из командной строки, но гораздо менее крутым способом. "from __main__ import ..." позволяет вам использовать код из основного модуля внутри искусственной среды, созданной timeit.

Стоит отметить, что это удобная оболочка для Timer(...).timeit(...), поэтому она не особенно хороша для тайминга. Лично я предпочитаю использовать Timer, как показано выше.


Предупреждения

Есть несколько предостережений относительно timeit, которые применимы везде.

  • Накладные расходы не учитываются. Скажем, вы хотите засечь время x += 1, чтобы узнать, сколько времени занимает сложение:

    >>> python -m timeit -s "x = 0" "x += 1"
    10000000 loops, best of 3: 0.0476 usec per loop
    

    Ну, это не 0,0476 мкс. Вы только знаете, что это меньше. Все ошибки положительные.

    Поэтому попробуйте найти чистые накладные расходы:

    >>> python -m timeit -s "x = 0" ""      
    100000000 loops, best of 3: 0.014 usec per loop
    

    Это хорошие 30% накладных расходов только из-за времени! Это может сильно исказить относительные тайминги. Но на самом деле вас заботило только время добавления; время поиска для x также должно быть включено в служебные данные:

    >>> python -m timeit -s "x = 0" "x"
    100000000 loops, best of 3: 0.0166 usec per loop
    

    Разница не намного больше, но она есть.

  • Мутирующие методы опасны.

    python -m timeit -s "x = [0]*100000" "while x: x.pop()"
    10000000 loops, best of 3: 0.0436 usec per loop
    

    Но это совершенно неправильно! x — это пустой список после первой итерации. Вам нужно будет повторно инициализировать:

    >>> python -m timeit "x = [0]*100000" "while x: x.pop()"
    100 loops, best of 3: 9.79 msec per loop
    

    Но тогда у вас много накладных расходов. Учитывайте это отдельно.

    >>> python -m timeit "x = [0]*100000"                   
    1000 loops, best of 3: 261 usec per loop
    

    Обратите внимание, что здесь разумно вычитать накладные расходы только потому, что накладные расходы составляют очень небольшую часть времени.

person Veedrac    schedule 21.09.2013

Я считаю, что магические функции IPython %timeit и %%timeit проще в использовании, чем timeit.timeit (особенно при использовании блокнота ipython). Пара примеров здесь.

person Will Holmgren    schedule 21.09.2013

>>> "-".join(str(n) for n in range(100))
'0-1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31-32-33-34-35-36-37-38-39-40-41-42-43-44-45-46-47-48-49-50-51-52-53-54-55-56-57-58-59-60-61-62-63-64-65-66-67-68-69-70-71-72-73-74-75-76-77-78-79-80-81-82-83-84-85-86-87-88-89-90-91-92-93-94-95-96-97-98-99'
>>> 

Предположим, вы хотите выполнить эту команду.
Импортируйте timeit. Сделайте команду строкой, добавьте, сколько раз вы хотите ее запустить.

>>> timeit.timeit('"-".join(str(n) for n in range(100))', number=100)
0.011214537887298093

Документация
Этот документ действительно непонятен? Я нахожу это ясным.

person octref    schedule 21.09.2013
comment
что я имею в виду: я не понимаю, как использовать его для моего собственного типа функционального кода - person user65165; 21.09.2013