Содержание страницы
timeit – Измерение времени выполнения небольших фрагментов кода¶timeit – Measure execution time of small code snippets
Этот модуль предоставляет простой способ измерения времени выполнения небольших фрагментов кода Python. Он имеет как интерфейс командной строки, так и вызываемый интерфейс. Он позволяет избежать ряда распространённых ловушек при измерении времени выполнения. См. также введение Тима Питерса в главу «Алгоритмы» в книге Python Cookbook, опубликованной O’Reilly.
Модуль определяет следующий открытый класс:
- class timeit.Timer([stmt='pass'[, setup='pass'[, timer=<timer function>]]])¶
Класс для измерения скорости выполнения небольших фрагментов кода.
Конструктор принимает измеряемый оператор, дополнительный оператор для настройки и функцию таймера. Оба оператора по умолчанию равны 'pass'; функция таймера зависит от платформы (см. строку документации модуля). Операторы могут содержать символы новой строки, если они не содержат многострочные строковые литералы.
Для измерения времени выполнения первого оператора используйте метод timeit(). Метод repeat() – это удобная функция для вызова timeit() несколько раз и возврата списка результатов.
Параметры stmt и setup также могут принимать вызываемые объекты без аргументов. Это встраивает вызовы к ним в функцию таймера, которая затем выполняется с помощью timeit(). Обратите внимание, что в этом случае накладные расходы на измерение времени немного выше из-за дополнительных вызовов функций.
- Timer.print_exc([file=None])¶
Вспомогательная функция для вывода трассировки из кода, время выполнения которого измеряется.
Типичное использование:
t = Timer(...) # за пределами try/except try: t.timeit(...) # или t.repeat(...) except: t.print_exc()
Преимущество перед стандартным traceback в том, что будут отображаться строки исходного кода в скомпилированном шаблоне. Необязательный аргумент file определяет, куда отправляется traceback; по умолчанию он отправляется в sys.stderr.
- Timer.repeat([repeat=3[, number=1000000]])¶
Вызывает timeit() несколько раз.
Это удобная функция, которая многократно вызывает timeit(), возвращая список результатов. Первый аргумент указывает, сколько раз вызывать timeit(). Второй аргумент задаёт значение параметра number для timeit().
Примечание
Может возникнуть соблазн вычислить среднее и стандартное отклонение из вектора результатов и сообщить их. Однако это не очень полезно. В типичном случае наименьшее значение даёт нижнюю границу того, насколько быстро ваша машина может выполнить данный фрагмент кода; более высокие значения в векторе результатов обычно вызваны не изменчивостью скорости Python, а другими процессами, мешающими точности измерения времени. Поэтому min() результатов – вероятно, единственное число, которое вас должно интересовать. После этого следует посмотреть на весь вектор и применить здравый смысл, а не статистику.
- Timer.timeit([number=1000000])¶
Измеряет время выполнения number повторений основного оператора. Он выполняет оператор настройки один раз, а затем возвращает время, необходимое для выполнения основного оператора заданное число раз, измеряемое в секундах как число с плавающей запятой. Аргумент – это количество повторений цикла, по умолчанию один миллион. Основной оператор, оператор настройки и используемая функция таймера передаются конструктору.
Примечание
По умолчанию timeit() временно отключает сборку мусора во время измерения времени. Преимущество такого подхода в том, что он делает независимые измерения более сопоставимыми. Недостаток в том, что сборка мусора может быть важной составляющей производительности измеряемой функции. Если это так, сборку мусора можно снова включить, указав её в качестве первого оператора в строке setup. Например:
timeit.Timer('for i in range(10): oct(i)', 'gc.enable()').timeit()
Модуль также определяет две вспомогательные функции:
- timeit.repeat(stmt[, setup[, timer[, repeat=3[, number=1000000]]]])¶
- Создаёт экземпляр Timer с указанным оператором, кодом настройки и функцией таймера и запускает его метод repeat() с заданным количеством повторений и number выполнениями.
- timeit.timeit(stmt[, setup[, timer[, number=1000000]]])¶
- Создаёт экземпляр Timer с указанным оператором, кодом настройки и функцией таймера и запускает его метод timeit() с number выполнениями.
Интерфейс командной строки¶Command Line Interface
При вызове как программы из командной строки используется следующая форма:
python -m timeit [-n N] [-r N] [-s S] [-t] [-c] [-h] [statement ...]
где принимаются следующие опции:
- -n N/--number=N
- сколько раз выполнять 'statement'
- -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 секунды.
Функция таймера по умолчанию зависит от платформы. В Windows time.clock() имеет микросекундную точность, а time.time() имеет точность 1/60 секунды; в Unix time.clock() имеет точность 1/100 секунды, а time.time() гораздо более точен. На любой платформе функции таймера по умолчанию измеряют настенное время, а не время CPU. Это означает, что другие процессы, работающие на том же компьютере, могут влиять на измерения. Лучшее, что можно сделать при необходимости точных измерений, – это повторить измерение несколько раз и использовать лучшее время. Опция -r хорошо подходит для этого; по умолчанию 3 повторений, вероятно, достаточно в большинстве случаев. В Unix можно использовать time.clock() для измерения времени CPU.
Примечание
Существует некоторая базовая накладная нагрузка, связанная с выполнением оператора pass. Приведённый код не пытается её скрыть, но следует знать об этом. Базовую накладную нагрузку можно измерить, вызвав программу без аргументов.
Базовые накладные расходы различаются между версиями Python! Кроме того, для справедливого сравнения старых версий Python с Python 2.3 может потребоваться использовать опцию -O Python для старых версий, чтобы избежать измерения инструкций SET_LINENO.
Примеры¶Examples
Вот два примера сеансов (один с использованием командной строки, другой с использованием интерфейса модуля), которые сравнивают стоимость использования hasattr() против try/except для проверки отсутствующих и существующих атрибутов объектов.
% timeit.py 'try:' ' str.__bool__' 'except AttributeError:' ' pass'
100000 loops, best of 3: 15.7 usec per loop
% timeit.py 'if hasattr(str, "__bool__"): pass'
100000 loops, best of 3: 4.26 usec per loop
% timeit.py 'try:' ' int.__bool__' 'except AttributeError:' ' pass'
1000000 loops, best of 3: 1.43 usec per loop
% timeit.py 'if hasattr(int, "__bool__"): pass'
100000 loops, best of 3: 2.23 usec per loop
>>> import timeit
>>> s = """\
... try:
... str.__bool__
... except AttributeError:
... pass
... """
>>> t = timeit.Timer(stmt=s)
>>> print("%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000))
17.09 usec/pass
>>> s = """\
... if hasattr(str, '__bool__'): pass
... """
>>> t = timeit.Timer(stmt=s)
>>> print("%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000))
4.85 usec/pass
>>> s = """\
... try:
... int.__bool__
... except AttributeError:
... pass
... """
>>> t = timeit.Timer(stmt=s)
>>> print("%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000))
1.97 usec/pass
>>> s = """\
... if hasattr(int, '__bool__'): pass
... """
>>> t = timeit.Timer(stmt=s)
>>> print("%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000))
3.15 usec/pass
Чтобы предоставить модулю timeit доступ к определённым вами функциям, вы можете передать параметр setup, содержащий инструкцию import:
def test():
"Stupid test function"
L = [i for i in range(100)]
if __name__=='__main__':
from timeit import Timer
t = Timer("test()", "from __main__ import test")
print(t.timeit())