timeit — Измерение времени выполнения коротких фрагментов кода
Введено в версии 2.3.
Исходный код: Lib/timeit.py
Этот модуль предоставляет простой способ измерения времени выполнения небольших фрагментов кода Python. Он имеет как командную строку, так и функциональный интерфейс. Он избегает ряда распространённых ловушек при измерении времени выполнения. См. также введение Тима Петерса в главу «Алгоритмы» в книге «Python Cookbook», изданной издательством O’Reilly.
1. Базовые примеры
Следующий пример демонстрирует, как командная строка может использоваться для сравнения трёх различных выражений:
$ python -m timeit '"-".join(str(n) for n in range(100))' 10000 loops, best of 3: 40.3 usec per loop $ python -m timeit '"-".join([str(n) for n in range(100)])' 10000 loops, best of 3: 33.4 usec per loop $ python -m timeit '"-".join(map(str, range(100)))' 10000 loops, best of 3: 25.2 usec per loop
Это можно сделать из интерфейса Python с помощью:
>>> import timeit
>>> timeit.timeit('"-".join(str(n) for n in range(100))', number=10000)
0.8187260627746582
>>> timeit.timeit('"-".join([str(n) for n in range(100)])', number=10000)
0.7288308143615723
>>> timeit.timeit('"-".join(map(str, range(100)))', number=10000)
0.5858950614929199
Однако обратите внимание, что timeit будет автоматически определять количество повторений только при использовании командной строки. В разделе Примеры вы найдёте более сложные примеры.
2. Интерфейс Python
Модуль определяет три удобные функции и один публичный класс:
-
timeit.timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000) -
Создаёт экземпляр
Timerсо заданным оператором, кодом настройки и функцией таймера и выполняет его методtimeit()с заданным количеством выполнений.Введено в версии 2.6.
-
timeit.repeat(stmt='pass', setup='pass', timer=<default timer>, repeat=3, number=1000000) -
Создаёт экземпляр
Timerсо заданным оператором, кодом настройки и функцией таймера и выполняет его методrepeat()с заданным количеством повторений и выполнений.Введено в версии 2.6.
-
timeit.default_timer() -
Определяет функцию-таймер по умолчанию, платформозависимым образом. В Windows,
time.clock()имеет точность в микросекундах, ноtime.time()имеет точность 1/60 секунды. В Unix,time.clock()имеет точность 1/100 секунды, аtime.time()гораздо точнее. На любой платформеdefault_timer()измеряет время реального выполнения, а не процессорного времени. Это означает, что другие процессы, работающие на том же компьютере, могут повлиять на результат измерения.
-
class timeit.Timer(stmt='pass', setup='pass', timer=<timer function>) -
Класс для измерения скорости выполнения небольших фрагментов кода.
Конструктор принимает оператор для измерения, дополнительный оператор для настройки и функцию таймера. По умолчанию оба оператора — пустые; функция таймера зависит от платформы (см. строку документации модуля). stmt и setup также могут содержать несколько операторов, разделённых точкой с запятой или новой строкой, пока они не содержат многострочные строковые литералы.
Чтобы измерить время выполнения первого оператора, используйте метод
timeit(). Методrepeat()— это удобный способ вызватьtimeit()несколько раз и вернуть список результатов.Изменено в версии 2.6: Параметры stmt и setup теперь также могут принимать объекты, вызываемые без аргументов. Это встроит вызовы в функцию таймера, которая затем будет выполнена методом
timeit(). Обратите внимание, что в этом случае накладные расходы на измерение немного больше из-за дополнительных вызовов функций.-
timeit(number=1000000) -
Измеряет время выполнения number раз оператора. Этот метод выполняет оператор настройки один раз, а затем возвращает время, затраченное на выполнение основного оператора заданное количество раз, измеренное в секундах в виде числа с плавающей точкой. Аргумент — количество проходов цикла, по умолчанию один миллион. Оператор, оператор настройки и функция таймера передаются в конструктор.
Примечание
По умолчанию,
timeit()временно отключает сбор мусора во время измерения. Преимущество этого подхода — независимые измерения становятся более сравнимыми. Недостаток заключается в том, что сбор мусора может быть важной частью производительности измеряемой функции. В этом случае сбор мусора можно включить как первый оператор в строке setup. Например:timeit.Timer('for i in xrange(10): oct(i)', 'gc.enable()').timeit()
-
repeat(repeat=3, number=1000000) -
Вызов
timeit()несколько раз.Это удобная функция, которая вызывает метод
timeit()многократно и возвращает список результатов. Первый аргумент задаёт количество вызововtimeit(). Второй аргумент задаёт аргумент number дляtimeit().Примечание
Вкусно рассчитать среднее значение и стандартное отклонение из вектора результатов и сообщить их. Однако это не очень полезно. В типичном случае минимальное значение даёт нижнюю границу того, как быстро ваша машина может выполнить заданный фрагмент кода; большие значения в векторе результатов обычно не вызваны изменчивостью скорости Python, а влиянием других процессов на точность измерения. Поэтому
min()результата — вероятно, единственное число, которое вас должно заинтересовать. После этого следует посмотреть на весь вектор и применить здравый смысл, а не статистику.
-
print_exc(file=None) -
Вспомогательная функция для печати трассировки стека из отслеживаемого кода.
Типичное использование:
t = Timer(...) # outside the try/except try: t.timeit(...) # or t.repeat(...) except: t.print_exc()Преимущества перед стандартной трассировкой стека — отображение строк исходного кода в скомпилированной шаблоне. Необязательный аргумент file указывает, куда будет направлена трассировка; по умолчанию это
sys.stderr.
-
3. Интерфейс командной строки
При вызове программы из командной строки используется следующая форма:
python -m timeit [-n N] [-r N] [-s S] [-t] [-c] [-h] [statement ...]
Где понимаются следующие параметры:
-
-n N, --number=N -
сколько раз выполнить оператор
-
-r N, --repeat=N -
сколько раз повторить измерение времени (по умолчанию 3)
-
-s S, --setup=S -
оператор, выполняемый один раз в начале (по умолчанию
pass)
-
-t, --time -
использовать
time.time()(по умолчанию на всех платформах, кроме Windows)
-
-c, --clock -
использовать
time.clock()(по умолчанию в Windows)
-
-v, --verbose -
печать сырых результатов измерения времени; повторение для большей точности
-
-h, --help -
вывод короткой справки и выход
Многострочный оператор может быть задан указанием каждой строки как отдельного аргумента; отступы возможны, поместив аргумент в кавычки и используя ведущие пробелы. Несколько параметров -s обрабатываются аналогично.
Если -n не задан, подходящее количество циклов вычисляется, пытаясь последовательно возводить 10 в степени, пока общее время не достигнет как минимум 0,2 секунды.
Измерения default_timer() могут быть повлияны другими программами, работающими на одном компьютере, поэтому, когда необходима точная оценка времени, лучше повторить измерение несколько раз и использовать лучшее время. Опция -r хороша для этого; по умолчанию 3 повторения, вероятно, достаточно в большинстве случаев. В Unix можно использовать time.clock() для измерения времени работы процессора.
Примечание
Существует определённая базовая накладная стоимость, связанная с выполнением оператора pass. Данный код не пытается её скрыть, но вы должны знать о ней. Базовая накладная стоимость может измеряться вызовом программы без аргументов, и она может отличаться в разных версиях Python. Кроме того, для справедливого сравнения более ранних версий Python с Python 2.3, возможно, стоит использовать опцию Python -O (см. Оптимизации) для более старых версий, чтобы избежать измерения времени SET_LINENO инструкций.
4. Примеры
Можно предоставить оператор настройки, который выполняется только один раз в начале:
$ python -m timeit -s 'text = "sample string"; char = "g"' 'char in text' 10000000 loops, best of 3: 0.0877 usec per loop $ python -m timeit -s 'text = "sample string"; char = "g"' 'text.find(char)' 1000000 loops, best of 3: 0.342 usec per loop
>>> import timeit
>>> timeit.timeit('char in text', setup='text = "sample string"; char = "g"')
0.41440500499993504
>>> timeit.timeit('text.find(char)', setup='text = "sample string"; char = "g"')
1.7246671520006203
То же самое можно сделать, используя класс Timer и его методы:
>>> import timeit
>>> t = timeit.Timer('char in text', setup='text = "sample string"; char = "g"')
>>> t.timeit()
0.3955516149999312
>>> t.repeat()
[0.40193588800002544, 0.3960157959998014, 0.39594301399984033]
Следующие примеры показывают, как измерить время выполнения выражений, содержащих несколько строк. Здесь мы сравниваем стоимость использования hasattr() по сравнению с try/except для проверки отсутствующих и присутствующих атрибутов объекта:
$ python -m timeit 'try:' ' str.__nonzero__' 'except AttributeError:' ' pass' 100000 loops, best of 3: 15.7 usec per loop $ python -m timeit 'if hasattr(str, "__nonzero__"): pass' 100000 loops, best of 3: 4.26 usec per loop $ python -m timeit 'try:' ' int.__nonzero__' 'except AttributeError:' ' pass' 1000000 loops, best of 3: 1.43 usec per loop $ python -m timeit 'if hasattr(int, "__nonzero__"): pass' 100000 loops, best of 3: 2.23 usec per loop
>>> import timeit >>> # attribute is missing >>> s = """\ ... try: ... str.__nonzero__ ... except AttributeError: ... pass ... """ >>> timeit.timeit(stmt=s, number=100000) 0.9138244460009446 >>> s = "if hasattr(str, '__bool__'): pass" >>> timeit.timeit(stmt=s, number=100000) 0.5829014980008651 >>> >>> # attribute is present >>> s = """\ ... try: ... int.__nonzero__ ... except AttributeError: ... pass ... """ >>> timeit.timeit(stmt=s, number=100000) 0.04215312199994514 >>> s = "if hasattr(int, '__bool__'): pass" >>> timeit.timeit(stmt=s, number=100000) 0.08588060699912603
Чтобы предоставить модулю timeit доступ к определённым вами функциям, вы можете передать параметр setup, который содержит оператор импорта:
def test():
"""Stupid test function"""
L = []
for i in range(100):
L.append(i)
if __name__ == '__main__':
import timeit
print(timeit.timeit("test()", setup="from __main__ import test"))
© 2001–2020 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/2.7/library/timeit.html