timeit
— Измерение времени выполнения небольших фрагментов кода¶
Исходный код: Lib/timeit.py
Модуль предоставляет простой способ определения времени малых битов Python код. Имеет как Интерфейс командной строки, так и callable. Он позволяет избежать ряда обычных ловушек для измерения времени выполнения. См. также введение Tim Peters’а в главе «Алгоритмы» в Python Cookbook, опубликованную в O’Reilly.
Основные примеры¶
В следующем примере показано, как можно используемый Интерфейс командной строки для сравнения трех различных выражений:
$ python3 -m timeit '"-".join(str(n) for n in range(100))'
10000 loops, best of 5: 30.2 usec per loop
$ python3 -m timeit '"-".join([str(n) for n in range(100)])'
10000 loops, best of 5: 27.5 usec per loop
$ python3 -m timeit '"-".join(map(str, range(100)))'
10000 loops, best of 5: 23.2 usec per loop
Это может быть достигнуто за счет Интерфейс Python с:
>>> import timeit
>>> timeit.timeit('"-".join(str(n) for n in range(100))', number=10000)
0.3018611848820001
>>> timeit.timeit('"-".join([str(n) for n in range(100)])', number=10000)
0.2727368790656328
>>> timeit.timeit('"-".join(map(str, range(100)))', number=10000)
0.23702679807320237
Вызываемый также может быть передан из Интерфейс Python:
>>> timeit.timeit(lambda: "-".join(map(str, range(100))), number=10000)
0.19665591977536678
Однако timeit()
автоматически определяет количество повторений только при
используемый интерфейса командной строки. В Примеры разделе приведены
дополнительные примеры.
Интерфейс Python¶
Модуль определяет три удобные функции и публичный класс:
-
timeit.
timeit
(stmt='pass', setup='pass', timer=<default timer>, number=1000000, globals=None)¶ Создать
Timer
сущность с заданной функцией инструкция, setup код и timer и запускает ее методtimeit()
с number выполнением. Необязательный аргумент globals указывает пространство имен для выполнения кода.Изменено в версии 3.5: Добавлен необязательный параметр globals.
-
timeit.
repeat
(stmt='pass', setup='pass', timer=<default timer>, repeat=5, number=1000000, globals=None)¶ Создать
Timer
сущность с заданной функцией инструкция, setup код и timer и запустите ее методrepeat()
с заданным repeat счётчиком и number выполнений. Необязательный аргумент globals указывает пространство имен для выполнения кода.Изменено в версии 3.5: Добавлен необязательный параметр globals.
Изменено в версии 3.7: значение repeat по умолчанию изменено с 3 на 5.
-
timeit.
default_timer
()¶ Таймер по умолчанию, который всегда
time.perf_counter()
.Изменено в версии 3.3:
time.perf_counter()
теперь является таймером по умолчанию.
-
class
timeit.
Timer
(stmt='pass', setup='pass', timer=<timer function>, globals=None)¶ Класс скорости выполнения синхронизации небольших фрагментов кода.
Конструктор берет инструкция для синхронизации, дополнительный инструкция используемый для установки и функцию таймера. Оба инструкции значение по умолчанию -
'pass'
; функция таймера зависит от платформы (см. документ модуля string). stmt и setup могут также содержать несколько инструкции, разделенных;
или новыми строками, если они не содержат многострочных строка литералов. По умолчанию инструкция будет выполняться в пространстве имен timeit; этим поведением можно управлять путем передачи пространства имен в globals.Для измерения времени выполнения первой инструкции используйте метод
timeit()
. Методыrepeat()
иautorange()
являются удобными способами многократного вызоваtimeit()
.Время выполнения setup исключается из общего времени выполнения.
Параметры stmt и setup могут также принимать объекты, вызываемые без аргументов. Вызовы будут встроены в функцию таймера, которая затем будет выполняться
timeit()
. Следует отметить, что служебные данные синхронизации в этом случае немного больше из-за дополнительных вызовов функций.Изменено в версии 3.5: Добавлен необязательный параметр globals.
-
timeit
(number=1000000)¶ Время number расстрелов главных инструкция. При этом инструкция установки выполняется один раз, а затем возвращает время, необходимое для выполнения основного инструкция, несколько раз, измеренное в секундах как float. Аргумент - это число раз в цикле, по умолчанию равное одному миллиону. Главный инструкция, инструкция установки и используемый функция таймера передаются конструктору.
Примечание
По умолчанию
timeit()
временно отключает сборщик мусора во время синхронизации. Преимущество этого подхода в том, что он делает независимые тайминги более сопоставимыми. Недостатком является то, что GC может быть важным компонентом эффективности измеряемой функции. Если это так, GC может быть повторно включен в качестве первого инструкция в setup строке. Например:timeit.Timer('for i in range(10): oct(i)', 'gc.enable()').timeit()
-
autorange
(callback=None)¶ Автоматически определяет количество вызовов
timeit()
.Это удобная функция, которая вызывает
timeit()
повторно, так что общее время >= 0.2 секунды, возвращая возможное (количество циклов, время, занятое для этого числа циклов). Он вызываетtimeit()
с возрастающими числами из последовательности 1, 2, 5, 10, 20, 50, … пока время не составит не менее 0,2 секунды.Если callback передано и не
None
, то будет вызываться после каждого пробного с двумя аргументами:callback(number, time_taken)
.Добавлено в версии 3.6.
-
repeat
(repeat=5, number=1000000)¶ Вызов
timeit()
несколько раз.Это удобная функция, которая вызывает
timeit()
повторно, возвращая список результатов. Первый аргумент указывает количество вызововtimeit()
. Второй аргумент указывает number аргумент дляtimeit()
.Примечание
Соблазнительно вычислить среднее и стандартное отклонение от вектора результата и сообщить об этом. Однако это не очень полезно. В типичном случае самый низкий значение дает нижнюю границу для того, как быстро машина может запустить данный фрагмент код; более высокие значения вектора результата обычно вызваны не изменчивостью скорости Python’а, а другими процессами, мешающими точности синхронизации. Так что
min()
результата, наверное, единственное число, которое вас должно заинтересовать. После этого следует посмотреть на весь вектор и применить здравый смысл, а не статистику.Изменено в версии 3.7: Значение repeat по умолчанию изменено с 3 на 5.
-
print_exc
(file=None)¶ Помощник для печати трейсбэка из временного кода.
Типичное использование:
t = Timer(...) # вне try/except try: t.timeit(...) # или t.repeat(...) except Exception: t.print_exc()
Преимущество по сравнению со стандартным трейсбэком заключается в том, что в скомпилированном шаблоне отображаются исходные строки. Необязательный аргумент file указывает место отправки трейсбэк; значение по умолчанию -
sys.stderr
.
-
Интерфейс командной строки¶
При вызове программы из командной строки используемый следующая форма:
python -m timeit [-n N] [-r N] [-u U] [-s S] [-h] [statement ...]
Где понимаются следующие варианты:
-
-n
N
,
--number
=N
¶ сколько раз выполнить инструкцию
-
-r
N
,
--repeat
=N
¶ сколько раз повторять таймер (по умолчанию 5)
-
-s
S
,
--setup
=S
¶ инструкция для выполнения один раз (по умолчанию
pass
)
-
-p
,
--process
¶
измерить время процесса, а не время обхода, используя
time.process_time()
вместоtime.perf_counter()
, что является значением по умолчаниюДобавлено в версии 3.3.
-
-u
,
--unit
=U
¶ определяют единицу времени для вывода таймера; может выбрать nsec, usec, msec или sec
Добавлено в версии 3.5.
-
-v
,
--verbose
¶
печать необработанных результатов синхронизации; повтор для большей точности цифр
-
-h
,
--help
¶
распечатать короткое сообщение об использовании и выйти из программы
Многострочный инструкция может быть задан путем указания каждой строки в
качестве отдельного аргумента инструкция; строки с отступами можно заключить в
кавычки и использовать начальные пробелы. Несколько опций -s
обрабатываются одинаково.
Если -n
не дано, подходящее количество циклов вычисляется путем попытки
увеличения чисел из последовательности 1, 2, 5, 10, 20, 50,… пока общее время
не составит по меньшей мере 0,2 секунды.
default_timer()
измерения могут быть затронуты другими программами, работающими на
той же машине, поэтому лучше всего, когда необходимо точное время, повторить
время несколько раз и использовать лучшее время. Вариант -r
хорош для
этого; по умолчанию 5 повторов, вероятно, достаточно в большинстве случаев. Для
измерения времени ЦПУ можно использовать time.process_time()
.
Примечание
С выполнением инструкция передачи связаны определенные накладные расходы базовой линии. Здесь код не пытается скрыть, но вы должны знать об этом. Базовые издержки могут быть измерены путем вызова программы без аргументов, и они могут отличаться между Python версиями.
Примеры¶
Можно предоставить инструкция настройки, которая выполняется только один раз в начале:
$ python -m timeit -s 'text = "sample string"; char = "g"' 'char in text'
5000000 loops, best of 5: 0.0877 usec per loop
$ python -m timeit -s 'text = "sample string"; char = "g"' 'text.find(char)'
1000000 loops, best of 5: 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.40183617287970225, 0.37027556854118704, 0.38344867356679524, 0.3712595970846668, 0.37866875250654886]
В следующих примерах показано, как создавать временные выражения, содержащие
несколько строк. Здесь мы сравним стоимость использования hasattr()
с
try
/except
для проверки отсутствующих и текущих атрибуты:
объектов
$ python -m timeit 'try:' ' str.__bool__' 'except AttributeError:' ' pass'
20000 loops, best of 5: 15.7 usec per loop
$ python -m timeit 'if hasattr(str, "__bool__"): pass'
50000 loops, best of 5: 4.26 usec per loop
$ python -m timeit 'try:' ' int.__bool__' 'except AttributeError:' ' pass'
200000 loops, best of 5: 1.43 usec per loop
$ python -m timeit 'if hasattr(int, "__bool__"): pass'
100000 loops, best of 5: 2.23 usec per loop
>>> import timeit
>>> # attribute is missing
>>> s = """\
... try:
... str.__bool__
... 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.__bool__
... 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 = [i for i in range(100)]
if __name__ == '__main__':
import timeit
print(timeit.timeit("test()", setup="from __main__ import test"))
Другой вариант - передать globals()
параметру globals, что приведет к
выполнению код в текущем глобальном пространстве имен. Это может быть
удобнее, чем индивидуальное определение импорта:
def f(x):
return x**2
def g(x):
return x**4
def h(x):
return x**8
import timeit
print(timeit.timeit('[func(42) for func in (f,g,h)]', globals=globals()))