Как мне использовать timeit для сравнения производительности моих собственных функций, таких как "insertion_sort" и "tim_sort"?
Переведено автоматически
Ответ 1
Если вы хотите использовать timeit в интерактивном сеансе Python, есть два удобных варианта:
Используйте оболочку IPython. Она имеет удобную %timeit специальную функцию:
In [1]: deff(x): ...: return x*x ...:
In [2]: %timeit for x inrange(100): f(x) 100000 loops, best of 3: 20.3 us per loop
В стандартном интерпретаторе Python вы можете получить доступ к функциям и другим именам, которые вы определили ранее во время интерактивного сеанса, импортировав их из __main__ в инструкции setup:
>>> deff(x): ... return x * x ... >>> import timeit >>> timeit.repeat("for x in range(100): f(x)", "from __main__ import f", number=100000) [2.0640320777893066, 2.0876040458679199, 2.0520210266113281]
Ответ 2
Способ timeit работы заключается в том, чтобы запустить установочный код один раз, а затем выполнить повторные вызовы серии инструкций. Итак, если вы хотите протестировать сортировку, требуется некоторая осторожность, чтобы один проход при сортировке на месте не повлиял на следующий проход с уже отсортированными данными (что, конечно, сделало бы Timsort действительно блестящим, потому что он работает лучше всего, когда данные уже частично упорядочены).
Вот пример того, как настроить тест для сортировки:
>>> import timeit
>>> setup = ''' import random
random.seed('slartibartfast') s = [random.random() for i in range(1000)] timsort = list.sort '''
Обратите внимание, что серия инструкций создает новую копию несортированных данных на каждом проходе.
Также обратите внимание на методику синхронизации, заключающуюся в запуске набора измерений семь раз и сохранении только наилучшего времени — это действительно может помочь уменьшить искажения измерений из-за других процессов, запущенных в вашей системе.
Ответ 3
Я открою вам секрет: лучший способ использовать 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. Я предлагаю избегать этого, потому что анализ и синхронизация просто лучше выполняются в командной строке. Вместо этого я обычно создаю сценарии оболочки:
Обычно вам следует комбинировать это с functools.partial вместо lambda: ..., чтобы снизить накладные расходы. Таким образом, у вас может получиться что-то вроде:
который дал бы вам что-то более близкое к интерфейсу из командной строки, но в гораздо менее крутой манере. "from __main__ import ..." позволяет вам использовать код из вашего основного модуля внутри искусственной среды, созданной timeit.
Стоит отметить, что это удобная оболочка для Timer(...).timeit(...) и поэтому она не особенно хороша с синхронизацией. Лично я предпочитаю использовать Timer(...).repeat(...) то, что я показал выше.
Предупреждения
Есть несколько предостережений с 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
Обратите внимание, что вычитание накладных расходов здесь разумно только потому, что накладные расходы составляют небольшую долю времени.
Для вашего примера стоит отметить, что как сортировка по вставке, так и сортировка по времени имеют совершенно необычное поведение по времени для уже отсортированных списков. Это означает, что вам потребуется random.shuffle промежуточная сортировка, если вы хотите избежать нарушения ваших таймингов.
Ответ 4
Если вы хотите быстро сравнить два блока кода / функций, вы могли бы сделать: