Я понимаю концепцию того, что делает timeit
, но не уверен, как реализовать это в моем коде.
Как я могу сравнить две функции, скажем insertion_sort
и tim_sort
, с timeit
?
Я понимаю концепцию того, что делает timeit
, но не уверен, как реализовать это в моем коде.
Как я могу сравнить две функции, скажем insertion_sort
и tim_sort
, с timeit
?
timeit работает так, чтобы запустить установку кодируйте один раз, а затем повторно обращайтесь к серии операторов. Итак, если вы хотите протестировать сортировку, необходимо проявить осторожность, чтобы один проход сортировки на месте не повлиял на следующий проход с уже отсортированными данными (что, конечно, сделало бы Timsort действительно великолепен, потому что он работает лучше всего, когда данные уже частично упорядочены).
Вот пример того, как настроить тест для сортировки:
>>> import timeit
>>> setup = '''
import random
random.seed('slartibartfast')
s = [random.random() for i in range(1000)]
timsort = list.sort
'''
>>> print min(timeit.Timer('a=s[:]; timsort(a)', setup=setup).repeat(7, 1000))
0.334147930145
Обратите внимание, что серия операторов создает новую копию несортированных данных на каждом проходе.
Также обратите внимание на временную технику: запуск пакета измерений семь раз и сохранение только лучшего времени - это действительно может помочь уменьшить искажения измерений из-за других процессов, запущенных в вашей системе.
Это мои советы по правильному использованию timeit. Надеюсь это поможет :-)
timsort(a)
и без него и обратите внимание на разницу :-)
- person Raymond Hettinger; 07.02.2012
.repeat(7,1000)
уже делает это (используя то же семя)! Так что ваше решение идеально IMO.
- person max; 04.04.2012
.repeat(7, 1000)
против .repeat(2, 3500)
против .repeat(35, 200
), должно зависеть от того, как ошибка из-за загрузки системы сравнивается с ошибкой из-за изменчивости ввода. В крайнем случае, если ваша система всегда находится под большой нагрузкой и вы видите длинный тонкий хвост слева от распределения времени выполнения (когда вы ловите его в редком состоянии ожидания), вы можете даже найти .repeat(7000,1)
более полезным, чем .repeat(7,1000)
если вы не можете запланировать более 7000 пробежек.
- person max; 04.04.2012
it
над ними, а затем времени 'a=next(it); timsort(a)'
?
- person Stefan Pochmann; 26.12.2017
.repeat(7000, 1)
?
- person binaryfunt; 04.06.2021
setup
на каждой итерации, необходимо только в том случае, если ваша функция изменяет эти параметры, например, сортировка на месте. E. g. для sorted()
вам не понадобится копия. Конечно, кто-то хочет проверить производительность любой функции, с побочными эффектами или без них. Но если вы избегаете функций с побочными эффектами, можно безопасно исключить оператор копирования. Теперь, если вы хотите сравнить оба типа функций и получить действительно точные измерения, вы можете вычесть продолжительность механизма копирования из тестов, в которых вы его применили.
- person examiner; 08.06.2021
Если вы хотите использовать timeit
в интерактивном сеансе Python, есть два удобных варианта:
Используйте оболочку IPython. В нем есть удобная %timeit
специальная функция:
In [1]: def f(x):
...: return x*x
...:
In [2]: %timeit for x in range(100): f(x)
100000 loops, best of 3: 20.3 us per loop
В стандартном интерпретаторе Python вы можете получить доступ к функциям и другим именам, которые вы определили ранее во время интерактивного сеанса, импортируя их из __main__
в операторе установки:
>>> def f(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]
from __main__ import f
. Я не думаю, что это так широко известно, как должно быть. Это полезно в таких случаях, когда выполняется синхронизация вызова функции или метода. В других случаях (определение времени для серии шагов) это менее полезно, поскольку приводит к накладным расходам на вызов функции.
- person Raymond Hettinger; 22.11.2011
%timeit f(x)
- person qed; 23.12.2014
sys._getframe(N).f_globals
) должны были быть по умолчанию с самого начала.
- person kxr; 06.05.2017
Открою вам секрет: лучший способ использовать 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(...).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
между сортировками, если вы хотите избежать потери времени.
timeit
Python из программы, но функционирует так же, как командная строка?.
- person Graham; 03.01.2019
timeit
выполняет pass
оператор, когда не указаны аргументы, что, конечно, занимает некоторое время. Если заданы какие-либо аргументы, pass
не будет выполняться, поэтому вычитание нескольких 0.014
мксек из каждого времени будет неправильным.
- person Arne; 22.03.2019
pass
почти свободна для исполнения; Дело в том, чтобы измерить тестовый аппарат.
- person Veedrac; 22.03.2019
pass
?
- person Arne; 22.03.2019
python -m 'pass' 'pass'
, и он был таким же быстрым, как и одиночный. Упс, может, стоило подумать об этом раньше.
- person Arne; 23.03.2019
time python script.py
отследить время выполнения всего скрипта из командной строки.
- person JonPizza; 27.08.2019
Если вы хотите быстро сравнить два блока кода / функций, вы можете сделать:
import timeit
start_time = timeit.default_timer()
func1()
print(timeit.default_timer() - start_time)
start_time = timeit.default_timer()
func2()
print(timeit.default_timer() - start_time)
Я считаю, что самый простой способ использовать timeit - из командной строки:
Учитывая test.py:
def InsertionSort(): ...
def TimSort(): ...
запустить время вот так:
% python -mtimeit -s'import test' 'test.InsertionSort()'
% python -mtimeit -s'import test' 'test.TimSort()'
для меня это самый быстрый способ:
import timeit
def foo():
print("here is my code to time...")
timeit.timeit(stmt=foo, number=1234567)
Это отлично работает:
python -m timeit -c "$(cat file_name.py)"
просто передайте весь свой код в качестве аргумента timeit:
import timeit
print(timeit.timeit(
"""
limit = 10000
prime_list = [i for i in range(2, limit+1)]
for prime in prime_list:
for elem in range(prime*2, max(prime_list)+1, prime):
if elem in prime_list:
prime_list.remove(elem)
"""
, number=10))
позволяет настроить один и тот же словарь в каждом из следующих и проверить время выполнения.
Аргумент установки в основном настраивает словарь
Номер - запустить код 1000000 раз. Не установка, а stmt
Когда вы запустите это, вы увидите, что индекс намного быстрее, чем получить. Вы можете запустить его несколько раз, чтобы увидеть.
Код в основном пытается получить значение c в словаре.
import timeit
print('Getting value of C by index:', timeit.timeit(stmt="mydict['c']", setup="mydict={'a':5, 'b':6, 'c':7}", number=1000000))
print('Getting value of C by get:', timeit.timeit(stmt="mydict.get('c')", setup="mydict={'a':5, 'b':6, 'c':7}", number=1000000))
Вот мои результаты, ваши будут отличаться.
по индексу: 0.20900007452246427
по: 0.54841166886888
Встроенный модуль timeit лучше всего работает из командной строки IPython.
Для функций времени из модуля:
from timeit import default_timer as timer
import sys
def timefunc(func, *args, **kwargs):
"""Time a function.
args:
iterations=3
Usage example:
timeit(myfunc, 1, b=2)
"""
try:
iterations = kwargs.pop('iterations')
except KeyError:
iterations = 3
elapsed = sys.maxsize
for _ in range(iterations):
start = timer()
result = func(*args, **kwargs)
elapsed = min(timer() - start, elapsed)
print(('Best of {} {}(): {:.9f}'.format(iterations, func.__name__, elapsed)))
return result
Пример использования интерпретатора Python REPL с функцией, принимающей параметры.
>>> import timeit
>>> def naive_func(x):
... a = 0
... for i in range(a):
... a += i
... return a
>>> def wrapper(func, *args, **kwargs):
... def wrapper():
... return func(*args, **kwargs)
... return wrapper
>>> wrapped = wrapper(naive_func, 1_000)
>>> timeit.timeit(wrapped, number=1_000_000)
0.4458435332577161
timeit.timeit(lambda: naive_func(x), number=1_000_000)
имеет значение?
- person garej; 13.01.2021
Вы должны создать две функции, а затем запустить что-то похожее на это. Обратите внимание, вы хотите выбрать такое же количество запусков / запусков для сравнения яблока и яблока.
Это было протестировано в Python 3.7.
Вот код, который упрощает его копирование
!/usr/local/bin/python3
import timeit
def fibonacci(n):
"""
Returns the n-th Fibonacci number.
"""
if(n == 0):
result = 0
elif(n == 1):
result = 1
else:
result = fibonacci(n-1) + fibonacci(n-2)
return result
if __name__ == '__main__':
import timeit
t1 = timeit.Timer("fibonacci(13)", "from __main__ import fibonacci")
print("fibonacci ran:",t1.timeit(number=1000), "milliseconds")
gc.enable()
?
- person Robin Andrews; 14.06.2020
Garbage Collection
, который обычно деактивируется во время этих временных прогонов.
- person aronadaal; 09.07.2021