Автор оригинала: Doug Hellmann.
Цель:
Время выполнения небольших фрагментов кода Python.
Модуль timeit
предоставляет простой интерфейс для определения времени выполнения небольших фрагментов кода Python. Он использует зависящую от платформы функцию времени, чтобы обеспечить наиболее точный расчет времени и снижает влияние затрат на запуск или останов на расчет времени за счет многократного выполнения кода.
Содержание модуля
timeit
определяет единственный открытый класс, Timer
. Конструктор для Timer
принимает оператор для синхронизации и оператор “setup” (например, используемый для инициализации переменных). Операторы Python должны быть строками и могут включать встроенные символы новой строки.
Метод timeit ()
запускает оператор настройки один раз, затем повторно выполняет основной оператор и возвращает количество прошедшего времени. Аргумент timeit ()
определяет, сколько раз запускать оператор; по умолчанию – 1000000.
Базовый пример
Чтобы проиллюстрировать, как используются различные аргументы Timer
, вот простой пример, который печатает идентифицирующее значение при выполнении каждого оператора.
timeit_example.py
import timeit # using setitem t timeit.Timer("print('main statement')", "print('setup')") print('TIMEIT:') print(t.timeit(2)) print('REPEAT:') print(t.repeat(3, 2))
При запуске вывод показывает результаты повторных вызовов print ()
.
$ python3 timeit_example.py TIMEIT: setup main statement main statement 1.8429999999944324e-06 REPEAT: setup main statement main statement setup main statement main statement setup main statement main statement [1.4149999999976681e-06, 1.005999999997842e-06, 1.0179999999984646e-06]
timeit ()
выполняет оператор установки один раз, затем вызывает основной оператор count
раз. Он возвращает одно значение с плавающей запятой, представляющее совокупное количество времени, затраченного на выполнение основного оператора.
Когда используется repeat ()
, он вызывает timeit ()
несколько раз (в данном случае 3 раза), и все ответы возвращаются в виде списка.
Сохранение значений в словаре
В этом более сложном примере сравнивается количество времени, которое требуется для заполнения словаря большим количеством значений с использованием различных методов. Во-первых, для настройки Timer
необходимо несколько констант. Переменная setup_statement
инициализирует список кортежей, содержащих строки и целые числа, которые будут использоваться основными операторами для создания словарей, используя строки в качестве ключей и сохраняя целые числа в качестве связанных значений.
# A few constants range_size 1000 count 1000 setup_statement ';'.join([ "l = [(str(x), x) for x in range(1000)]", "d = {}", ])
Служебная функция show_results ()
предназначена для печати результатов в удобном формате. Метод timeit ()
возвращает количество времени, необходимое для повторного выполнения оператора. Вывод show_results ()
преобразует это в количество времени, которое требуется на одну итерацию, а затем дополнительно уменьшает значение до среднего количества времени, необходимого для сохранения одного элемента в словаре.
def show_results(result): "Print microseconds per pass and per item." global count, range_size per_pass 1000000 * (result / count) print('{:6.2f} usec/pass'.format(per_pass), end' ') per_item per_pass / range_size print('{:6.2f} usec/item'.format(per_item)) print("{} items".format(range_size)) print("{} iterations".format(count)) print()
Чтобы установить базовый уровень, в первой протестированной конфигурации используется __setitem __ ()
. Все другие варианты позволяют избежать перезаписи значений, уже имеющихся в словаре, поэтому эта простая версия должна быть самой быстрой.
Первый аргумент Timer
– это многострочная строка с сохраненными пробелами для обеспечения правильного анализа при запуске. Второй аргумент – это константа, установленная для инициализации списка значений и словаря.
# Using __setitem__ without checking for existing values first print('__setitem__:', end' ') t timeit.Timer( textwrap.dedent( """ for s, i in l: d[s] = i """), setup_statement, ) show_results(t.timeit(numbercount))
В следующем варианте используется setdefault ()
, чтобы гарантировать, что значения, уже содержащиеся в словаре, не будут перезаписаны.
# Using setdefault print('setdefault :', end' ') t timeit.Timer( textwrap.dedent( """ for s, i in l: d.setdefault(s, i) """), setup_statement, ) show_results(t.timeit(numbercount))
Этот метод добавляет значение, только если возникает исключение KeyError
при поиске существующего значения.
# Using exceptions print('KeyError :', end' ') t timeit.Timer( textwrap.dedent( """ for s, i in l: try: existing = d[s] except KeyError: d[s] = i """), setup_statement, ) show_results(t.timeit(numbercount))
И последний метод использует « in
», чтобы определить, есть ли в словаре конкретный ключ.
# Using "in" print('"not in" :', end' ') t timeit.Timer( textwrap.dedent( """ for s, i in l: if s not in d: d[s] = i """), setup_statement, ) show_results(t.timeit(numbercount))
При запуске скрипт выдает следующий результат.
$ python3 timeit_dictionary.py 1000 items 1000 iterations __setitem__: 62.47 usec/pass 0.06 usec/item setdefault : 122.70 usec/pass 0.12 usec/item KeyError : 60.78 usec/pass 0.06 usec/item "not in" : 55.79 usec/pass 0.06 usec/item
Это время для MacMini и будет зависеть от того, какое оборудование используется и какие другие программы запущены в системе. Поэкспериментируйте с переменными range_size
и count
, поскольку разные комбинации будут давать разные результаты.
Из командной строки
В дополнение к программному интерфейсу timeit
предоставляет интерфейс командной строки для тестирования модулей без инструментов.
Чтобы запустить модуль, используйте параметр -m
для интерпретатора Python, чтобы найти модуль и рассматривать его как основную программу:
$ python3 -m timeit
Например, чтобы получить помощь:
$ python3 -m timeit -h Tool for measuring execution time of small code snippets. This module avoids a number of common traps for measuring execution times. See also Tim Peters' introduction to the Algorithms chapter in the Python Cookbook, published by O'Reilly. ...
Аргумент statement
работает в командной строке немного иначе, чем аргумент для Timer
. Вместо использования одной длинной строки передайте каждую строку инструкций как отдельный аргумент командной строки. Для отступа строк (например, внутри цикла) вставляйте пробелы в строку, заключая ее в кавычки.
$ python3 -m timeit -s \ \ "for i in range(1000):" \ " d[str(i)] = i" 1000 loops, best of 5: 332 usec per loop
Также можно определить функцию с более сложным кодом, а затем вызвать функцию из командной строки.
timeit_setitem.py
def test_setitem(range_size1000): l [(str(x), x) for x in range(range_size)] d {} for s, i in l: d[s] i
Чтобы запустить тест, передайте код, который импортирует модули и запускает функцию тестирования.
$ python3 -m timeit \ "import timeit_setitem; timeit_setitem.test_setitem()" 1000 loops, best of 5: 376 usec per loop
Смотрите также
- стандартная библиотека документации для timeit
- profile – модуль
profile
также полезен для анализа производительности. - Монотонные часы – Обсуждение монотонных часов из модуля
time
.