Spec-Zone.ru › Python 2.7

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() для измерения времени работы процессора.

END_OF_DOCUMENT_MARKER ```

Примечание

Существует определённая базовая накладная стоимость, связанная с выполнением оператора 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API