profile.md
1> **Источник:** https://python-all.ru/3.0/library/profile.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# Профилировщики Python89Авторские права © 1994, InfoSeek Corporation, все права защищены.1011Автор: Джеймс Роскинд. [\[1\]](https://python-all.ru/3.0/library/profile.html#id2)1213Настоящим предоставляется бесплатное разрешение на использование, копирование, изменение и распространение этого программного обеспечения Python и связанной с ним документации для любых целей (при условии соблюдения ограничения, изложенного в следующем предложении) при условии, что указанное выше уведомление об авторских правах присутствует во всех копиях, и что как это уведомление об авторских правах, так и данное уведомление о разрешении включены в сопроводительную документацию, и что название InfoSeek не используется в рекламе или публикациях, связанных с распространением программного обеспечения, без специального письменного разрешения. Это разрешение явно ограничивается копированием и изменением программного обеспечения с сохранением его на Python, скомпилированном Python или других языках (например, C) при условии, что измененный или производный код импортируется исключительно в модуль Python.1415КОРПОРАЦИЯ INFOSEEK ОТКАЗЫВАЕТСЯ ОТ ВСЕХ ГАРАНТИЙ В ОТНОШЕНИИ ЭТОГО ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ, ВКЛЮЧАЯ ВСЕ ПОДРАЗУМЕВАЕМЫЕ ГАРАНТИИ КОММЕРЧЕСКОЙ ПРИГОДНОСТИ И ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННОЙ ЦЕЛИ. НИ ПРИ КАКИХ ОБСТОЯТЕЛЬСТВАХ КОРПОРАЦИЯ INFOSEEK НЕ НЕСЕТ ОТВЕТСТВЕННОСТИ ЗА ЛЮБЫЕ ОСОБЫЕ, КОСВЕННЫЕ ИЛИ ПОБОЧНЫЕ УБЫТКИ ИЛИ ЗА ЛЮБЫЕ УБЫТКИ, ВОЗНИКШИЕ В РЕЗУЛЬТАТЕ ПОТЕРИ ДАННЫХ ИЛИ ПРИБЫЛИ, НЕЗАВИСИМО ОТ ТОГО, ОСНОВАНЫ ЛИ ОНИ НА ДОГОВОРЕ, ДЕЛИКТЕ ИЛИ ИНОМ ПРАВОНАРУШЕНИИ, ВОЗНИКШЕМ В РЕЗУЛЬТАТЕ ИСПОЛЬЗОВАНИЯ ЭТОГО ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ ИЛИ СВЯЗАННОГО С НИМ.1617## Введение в профилировщики1819*Профилировщик* – это программа, которая описывает производительность программы во время выполнения, предоставляя различные статистические данные. В этой документации описываются функции профилирования, предоставляемые модулями `cProfile`, `profile` и `pstats`. Этот профилировщик обеспечивает *детерминированное профилирование* программ Python. Он также предоставляет ряд инструментов для создания отчетов, позволяющих пользователям быстро анализировать результаты операции профилирования.2021Стандартная библиотека Python предоставляет два различных профилировщика:22231. `cProfile` рекомендуется для большинства пользователей; это расширение на C с умеренными накладными расходами, что делает его подходящим для профилирования долго работающих программ. Основан на `lsprof`, предоставленном Бреттом Розеном и Тедом Зоттером.242. `profile` – это чистый модуль Python, интерфейс которого имитируется `cProfile`. Добавляет значительные накладные расходы к профилируемым программам. Если вы пытаетесь расширить профилировщик каким-либо образом, эта задача может оказаться проще с этим модулем. Авторские права © 1994, InfoSeek Corporation.2526Модули `profile` и `cProfile` экспортируют один и тот же интерфейс, поэтому они в основном взаимозаменяемы; `cProfile` имеет гораздо меньшие накладные расходы, но является более новым и может быть недоступен на всех системах. `cProfile` на самом деле является слоем совместимости поверх внутреннего модуля `_lsprof`.2728## Краткое руководство пользователя2930Этот раздел предназначен для пользователей, которые «не хотят читать руководство». В нём даётся очень краткий обзор, и он позволяет быстро выполнить профилирование существующего приложения.3132Чтобы профилировать приложение с главной точкой входа `foo()`, вы должны добавить следующее в ваш модуль:3334```python35import cProfile36cProfile.run('foo()')37```3839(Используйте `profile` вместо `cProfile`, если последний недоступен в вашей системе.)4041Вышеуказанное действие приведет к запуску `foo()` и выводу ряда информационных строк (профиля). Вышеописанный подход наиболее полезен при работе с интерпретатором. Если вы хотите сохранить результаты профилирования в файл для последующего просмотра, вы можете указать имя файла в качестве второго аргумента функции `run()`:4243```python44import cProfile45cProfile.run('foo()', 'fooprof')46```4748Файл `cProfile.py` также можно вызвать как скрипт для профилирования другого скрипта. Например:4950```python51python -m cProfile myscript.py52```5354`cProfile.py` принимает два необязательных аргумента в командной строке:5556```python57cProfile.py [-o output_file] [-s sort_order]58```5960[*-s*](https://python-all.ru/3.0/using/cmdline.html#cmdoption-s) применяется только к стандартному выводу (*-o* не указан). Смотрите документацию `Stats` для получения допустимых значений сортировки.6162Когда вы хотите просмотреть профиль, следует использовать методы модуля `pstats`. Обычно загрузка статистических данных выполняется следующим образом:6364```python65import pstats66p = pstats.Stats('fooprof')67```6869Класс `Stats` (приведенный выше код только что создал экземпляр этого класса) имеет множество методов для обработки и вывода данных, которые были только что прочитаны в `p`. Когда вы запустили [`cProfile.run()`](https://python-all.ru/3.0/library/profile.html#cProfile.run) выше, выведенный результат представлял собой результат трех вызовов методов:7071```python72p.strip_dirs().sort_stats(-1).print_stats()73```7475Первый метод удалил лишний путь из всех имен модулей. Второй метод отсортировал все записи в соответствии со стандартной строкой модуль/строка/имя, которая выводится. Третий метод распечатал всю статистику. Вы можете попробовать следующие вызовы сортировки:7677```python78p.sort_stats('name')79p.print_stats()80```8182Первый вызов сортирует список по имени функции, а второй вызов выводит статистику. Вот несколько интересных вызовов для экспериментов:8384```python85p.sort_stats('cumulative').print_stats(10)86```8788Это сортирует профиль по суммарному времени в функции и затем выводит только десять наиболее значимых строк. Чтобы понять, какие алгоритмы занимают время, следует использовать приведённую выше строку.8990Чтобы увидеть, какие функции много циклится и занимают много времени, можно сделать:9192```python93p.sort_stats('time').print_stats(10)94```9596для сортировки по времени, затраченному внутри каждой функции, и вывода статистики для десяти первых функций.9798Можно также попробовать:99100```python101p.sort_stats('file').print_stats('__init__')102```103104Это отсортирует всю статистику по имени файла, а затем выведет статистику только для методов инициализации классов (поскольку они содержат `__init__` в названии). В качестве последнего примера можно попробовать:105106```python107p.sort_stats('time', 'cum').print_stats(.5, 'init')108```109110Эта строка сортирует статистику по первичному ключу – времени, и вторичному ключу – совокупному времени, а затем выводит часть статистики. А именно: сначала список уменьшается до 50% (ср. `.5`) от исходного размера, затем сохраняются только строки, содержащие `init`, и выводится этот под-под-список.111112Если вам интересно, какие функции вызывали вышеупомянутые функции, теперь (`p` всё ещё отсортирован по последнему критерию) можно выполнить:113114```python115p.print_callers(.5, 'init')116```117118и будет получен список вызывающих для каждой из перечисленных функций.119120Для более широких возможностей придётся прочитать руководство или догадаться, что делают следующие функции:121122```python123p.print_callees()124p.add('fooprof')125```126127При запуске в качестве скрипта модуль `pstats` является браузером статистики для чтения и изучения дампов профиля. Он имеет простой построчный интерфейс (реализованный с помощью [`cmd`](https://python-all.ru/3.0/library/cmd.html#module-cmd)) и интерактивную справку.128129## Что такое детерминированное профилирование?130131*Deterministic profiling* is meant to reflect the fact that all *function call*, *function return*, and *exception* events are monitored, and precise timings are made for the intervals between these events (during which time the user’s code is executing). In contrast, *statistical profiling* (which is not done by this module) randomly samples the effective instruction pointer, and deduces where time is being spent. The latter technique traditionally involves less overhead (as the code does not need to be instrumented), but provides only relative indications of where time is being spent.132133В Python, поскольку во время выполнения активен интерпретатор, для детерминированного профилирования не требуется наличие инструментированного кода. Python автоматически предоставляет *ловушку* (необязательный колбэк) для каждого события. Кроме того, интерпретируемая природа Python обычно вносит так много накладных расходов на выполнение, что детерминированное профилирование в типичных приложениях добавляет лишь небольшие дополнительные накладные расходы. В результате детерминированное профилирование не так дорого, но при этом предоставляет обширную статистику времени выполнения программы на Python.134135Статистику количества вызовов можно использовать для выявления ошибок в коде (неожиданные количества) и для определения возможных точек встраивания (высокое количество вызовов). Статистику внутреннего времени можно использовать для выявления «горячих циклов», которые следует тщательно оптимизировать. Статистику суммарного времени следует использовать для выявления высокоуровневых ошибок в выборе алгоритмов. Обратите внимание, что нестандартная обработка суммарного времени в этом профилировщике позволяет напрямую сравнивать статистику рекурсивных реализаций алгоритмов с итеративными.136137## Справочное руководство – `profile` и `cProfile`138139Основная точка входа для профилировщика – глобальная функция `profile.run()` (соотв. [`cProfile.run()`](https://python-all.ru/3.0/library/profile.html#cProfile.run)). Обычно она используется для создания информации профилирования. Отчеты форматируются и выводятся с помощью методов класса [`pstats.Stats`](https://python-all.ru/3.0/library/profile.html#pstats.Stats). Ниже приводится описание всех этих стандартных точек входа и функций. Для более глубокого изучения некоторого кода рекомендуется прочитать раздел о расширениях профилировщика, в котором обсуждается, как вывести «лучшие» профилировщики из представленных классов, или прочитать исходный код этих модулей.140141#### `[cProfile.run]cProfile.run(command[, filename])`142143Эта функция принимает один аргумент, который можно передать функции [`exec()`](https://python-all.ru/3.0/library/functions.html#exec), и необязательное имя файла. Во всех случаях эта процедура пытается выполнить [`exec()`](https://python-all.ru/3.0/library/functions.html#exec) свой первый аргумент и собирает статистику профилирования из выполнения. Если имя файла не указано, эта функция автоматически выводит простой отчет о профилировании, отсортированный по стандартной строке имени (файл/строка/имя-функции), которая представлена в каждой строке. Ниже приведен типичный вывод такого вызова:144145```python146 2706 function calls (2004 primitive calls) in 4.504 CPU seconds147148Ordered by: standard name149150ncalls tottime percall cumtime percall filename:lineno(function)151 2 0.006 0.003 0.953 0.477 pobject.py:75(save_objects)152 43/3 0.533 0.012 0.749 0.250 pobject.py:99(evaluate)153 ...154```155156Первая строка показывает, что было отслежено 2706 вызовов. Из этих вызовов 2004 были *примитивными*. Мы определяем *примитивный* как вызов, который не был вызван рекурсией. Следующая строка: `Ordered by: standard name`, указывает, что для сортировки вывода использовалась текстовая строка в крайнем правом столбце. Заголовки столбцов включают:157158**ncalls**159160– количество вызовов,161162**tottime**163164для общего времени, затраченного в данной функции (исключая время, затраченное на вызовы подфункций),165166**percall**167168– результат деления169170`tottime`171172на173174`ncalls`175176**cumtime**177178общее время, затраченное в этой и всех подфункциях (от вызова до выхода). Это значение точное179180*даже*181182для рекурсивных функций.183184**percall**185186– результат деления187188`cumtime`189190на количество первичных вызовов191192**filename:lineno(function)**193194– предоставляет соответствующие данные каждой функции195196Когда в первом столбце два числа (например, `43/3`), второе – это количество примитивных вызовов, а первое – фактическое количество вызовов. Обратите внимание: если функция не рекурсивна, эти два значения совпадают, и печатается только одно число.197198#### `[cProfile.runctx]cProfile.runctx(command, globals, locals[, filename])`199200Эта функция аналогична201202[`run()`](https://python-all.ru/3.0/library/profile.html#cProfile.run)203204, но с дополнительными аргументами для передачи словарей globals и locals для строки205206*command*207208.209210Анализ данных профилировщика выполняется с использованием класса `Stats`.211212> **Примечание**213>214> Класс `Stats` определён в модуле `pstats`.215216#### `[pstats.Stats]class pstats.Stats(filename[, stream=sys.stdout[, ...]])`217218Этот конструктор класса создаёт экземпляр «объекта статистики» из *имени файла* (или набора имён файлов). Объекты [`Stats`](https://python-all.ru/3.0/library/profile.html#pstats.Stats) управляются методами для вывода полезных отчётов. Вы можете указать альтернативный выходной поток данных, задав именованный аргумент `stream`.219220Файл, выбранный указанным конструктором, должен быть создан соответствующей версией `profile` или `cProfile`. В частности, *не* гарантируется совместимость файлов с будущими версиями этого профилировщика, и нет совместимости с файлами, созданными другими профилировщиками. Если предоставлено несколько файлов, вся статистика для одинаковых функций будет объединена, так что общий вид нескольких процессов можно рассмотреть в одном отчёте. Если необходимо объединить дополнительные файлы с данными в существующем объекте [`Stats`](https://python-all.ru/3.0/library/profile.html#pstats.Stats), можно использовать метод [`add()`](https://python-all.ru/3.0/library/profile.html#pstats.Stats.add).221222### Класс [`Stats`](https://python-all.ru/3.0/library/profile.html#pstats.Stats)223224Объекты [`Stats`](https://python-all.ru/3.0/library/profile.html#pstats.Stats) имеют следующие методы:225226#### `[pstats.Stats.strip_dirs]Stats.strip_dirs()`227228Этот метод класса229230[`Stats`](https://python-all.ru/3.0/library/profile.html#pstats.Stats)231232удаляет все начальные пути из имён файлов. Он очень полезен для уменьшения размера вывода, чтобы он умещался (примерно) в 80 столбцов. Этот метод изменяет объект, и удалённая информация теряется. После выполнения операции удаления путей считается, что записи объекта находятся в «случайном» порядке, как сразу после инициализации и загрузки объекта. Если233234[`strip_dirs()`](https://python-all.ru/3.0/library/profile.html#pstats.Stats.strip_dirs)235236делает два имени функций неразличимыми (они находятся на одной строке одного и того же файла и имеют одинаковое имя функции), то статистика для этих двух записей накапливается в одну запись.237238#### `[pstats.Stats.add]Stats.add(filename[, ...])`239240Этот метод класса241242[`Stats`](https://python-all.ru/3.0/library/profile.html#pstats.Stats)243244добавляет дополнительные данные профилирования в текущий объект профилирования. Его аргументы должны ссылаться на файлы, созданные соответствующей версией245246`profile.run()`247248или249250[`cProfile.run()`](https://python-all.ru/3.0/library/profile.html#cProfile.run)251252. Статистика для функций с одинаковыми именами (по файлу, строке, имени) автоматически объединяется в единую статистику функции.253254#### `[pstats.Stats.dump_stats]Stats.dump_stats(filename)`255256Сохраняет данные, загруженные в объект257258[`Stats`](https://python-all.ru/3.0/library/profile.html#pstats.Stats)259260, в файл с именем261262*filename*263264. Файл создаётся, если его не существует, и перезаписывается, если он уже существует. Это эквивалентно одноимённому методу классов265266`profile.Profile`267268и269270`cProfile.Profile`271272.273274#### `[pstats.Stats.sort_stats]Stats.sort_stats(key[, ...])`275276Этот метод изменяет объект [`Stats`](https://python-all.ru/3.0/library/profile.html#pstats.Stats), сортируя его в соответствии с заданными критериями. Аргументом обычно является строка, определяющая основу сортировки (например: `'time'` или `'name'`).277278Когда указано несколько ключей, дополнительные ключи используются как вторичные критерии при равенстве всех предыдущих ключей. Например, `sort_stats('name', 'file')` отсортирует все записи по имени функции, а при совпадении (одинаковых именах функций) будет сортировать по имени файла.279280Для любых имен ключей можно использовать сокращения, если они однозначны. Ниже перечислены ключи, определенные на данный момент:281282| Допустимый аргумент | Значение |283| --- | --- |284| `'calls'` | количество вызовов |285| `'cumulative'` | совокупное время |286| `'file'` | имя файла |287| `'module'` | имя файла |288| `'pcalls'` | количество примитивных вызовов |289| `'line'` | номер строки |290| `'name'` | имя функции |291| `'nfl'` | имя/файл/строка |292| `'stdname'` | стандартное имя |293| `'time'` | внутреннее время |294295Обратите внимание, что все сортировки по статистике выполняются по убыванию (самые ресурсоёмкие элементы на первом месте), в то время как поиск по имени, файлу и номеру строки выполняется по возрастанию (в алфавитном порядке). Тонкое различие между `'nfl'` и `'stdname'` заключается в том, что стандартное имя – это сортировка имени в том виде, как оно печатается, что означает, что встроенные номера строк сравниваются необычным образом. Например, строки 3, 20 и 40 (при одинаковых именах файлов) появятся в строковом порядке 20, 3 и 40. Напротив, `'nfl'` выполняет числовое сравнение номеров строк. Фактически, `sort_stats('nfl')` эквивалентно `sort_stats('name', 'file', 'line')`.296297По соображениям обратной совместимости допускаются числовые аргументы `-1`, `0`, `1` и `2`. Они интерпретируются соответственно как `'stdname'`, `'calls'`, `'time'` и `'cumulative'`. Если используется этот старый формат (числовой), будет использован только один ключ сортировки (числовой), а дополнительные аргументы будут молча игнорироваться.298299#### `[pstats.Stats.reverse_order]Stats.reverse_order()`300301Этот метод класса302303[`Stats`](https://python-all.ru/3.0/library/profile.html#pstats.Stats)304305меняет порядок основного списка внутри объекта. Обратите внимание, что по умолчанию порядок по возрастанию или убыванию правильно выбирается на основе выбранного ключа сортировки.306307#### `[pstats.Stats.print_stats]Stats.print_stats([restriction, ...])`308309Этот метод класса [`Stats`](https://python-all.ru/3.0/library/profile.html#pstats.Stats) выводит отчёт, как описано в определении `profile.run()`.310311Порядок вывода зависит от последней операции [`sort_stats()`](https://python-all.ru/3.0/library/profile.html#pstats.Stats.sort_stats), выполненной над объектом (с учётом оговорок в [`add()`](https://python-all.ru/3.0/library/profile.html#pstats.Stats.add) и [`strip_dirs()`](https://python-all.ru/3.0/library/profile.html#pstats.Stats.strip_dirs)).312313Переданные аргументы (если есть) можно использовать для ограничения списка значимыми записями. Изначально список содержит все профилированные функции. Каждое ограничение – это либо целое число (для выбора определённого количества строк), либо десятичная дробь от 0.0 до 1.0 включительно (для выбора процентной доли строк), либо регулярное выражение (для сопоставления шаблону выводимого стандартного имени; начиная с Python 1.5b1 используется синтаксис регулярных выражений в стиле Perl, определённый модулем [`re`](https://python-all.ru/3.0/library/re.html#module-re)). Если указано несколько ограничений, они применяются последовательно. Например:314315```python316print_stats(.1, 'foo:')317```318319сначала ограничит вывод первыми 10% списка, а затем выведет только те функции, которые входят в имя файла `.*foo:`. В отличие от этого, команда:320321```python322print_stats('foo:', .1)323```324325ограничит список всеми функциями, имена файлов которых содержат `.*foo:`, а затем выведет только первые 10% из них.326327#### `[pstats.Stats.print_callers]Stats.print_callers([restriction, ...])`328329Этот метод класса [`Stats`](https://python-all.ru/3.0/library/profile.html#pstats.Stats) выводит список всех функций, которые вызывали каждую функцию в профилированной базе данных. Порядок соответствует тому, что предоставляется методом [`print_stats()`](https://python-all.ru/3.0/library/profile.html#pstats.Stats.print_stats), и определение аргумента ограничения также идентично. Каждый вызывающий выводится на отдельной строке. Формат немного отличается в зависимости от профилировщика, создавшего статистику:330331- В `profile` после каждого вызывающего элемента в скобках показывается число, указывающее, сколько раз был совершён этот конкретный вызов. Для удобства второе число без скобок справа повторяет совокупное время, затраченное в функции.332- В `cProfile` перед каждым вызывающим элементом указываются три числа: количество раз, когда был совершён этот конкретный вызов, а также общее и совокупное время, затраченное в текущей функции при её вызове этим конкретным вызывающим элементом.333334#### `[pstats.Stats.print_callees]Stats.print_callees([restriction, ...])`335336Этот метод класса337338[`Stats`](https://python-all.ru/3.0/library/profile.html#pstats.Stats)339340выводит список всех функций, которые были вызваны указанной функцией. Если не считать этой перемены направления вызовов (т.е. вызванные против вызывающих), аргументы и порядок сортировки идентичны методу341342[`print_callers()`](https://python-all.ru/3.0/library/profile.html#pstats.Stats.print_callers)343344.345346## Ограничения347348Одно ограничение связано с точностью информации о времени. Существует фундаментальная проблема с детерминированными профилировщиками, касающаяся точности. Наиболее очевидное ограничение состоит в том, что внутренние «часы» тикают с частотой (обычно) около 0,001 секунды. Следовательно, ни одно измерение не может быть точнее этих часов. Если сделать достаточно измерений, «ошибка» будет стремиться к усреднению. К сожалению, устранение этой первой ошибки приводит ко второму источнику ошибок.349350The second problem is that it “takes a while” from when an event is dispatched until the profiler’s call to get the time actually *gets* the state of the clock. Similarly, there is a certain lag when exiting the profiler event handler from the time that the clock’s value was obtained (and then squirreled away), until the user’s code is once again executing. As a result, functions that are called many times, or call many functions, will typically accumulate this error. The error that accumulates in this fashion is typically less than the accuracy of the clock (less than one clock tick), but it *can* accumulate and become very significant.351352Эта проблема более существенна для `profile`, чем для менее нагруженного `cProfile`. По этой причине `profile` предоставляет возможность самокалибровки для данной платформы, чтобы эту ошибку можно было устранить вероятностно (в среднем). После калибровки профилировщик будет точнее (в смысле наименьших квадратов), но иногда будет выдавать отрицательные числа (когда количество вызовов исключительно мало и боги вероятности против вас :-). ) *Не* пугайтесь отрицательных чисел в профиле. Они должны *только* появляться, если вы откалибровали профилировщик, и результаты на самом деле лучше, чем без калибровки.353354## Калибровка355356Профилировщик модуля `profile` вычитает константу из времени обработки каждого события, чтобы компенсировать накладные расходы на вызов функции времени и сохранение результатов. По умолчанию константа равна 0. Следующую процедуру можно использовать для получения лучшей константы для данной платформы (см. обсуждение в разделе «Ограничения» выше).357358```python359import profile360pr = profile.Profile()361for i in range(5):362 print(pr.calibrate(10000))363```364365Метод выполняет количество вызовов Python, заданное аргументом, напрямую и снова под профилировщиком, измеряя время для обоих случаев. Затем он вычисляет скрытые накладные расходы на каждое событие профилировщика и возвращает их как число с плавающей запятой. Например, на Pentium 800 МГц под Windows 2000 с использованием time.clock() в качестве таймера это магическое число составляет около 12.5e-6.366367Цель этого упражнения – получить достаточно стабильный результат. Если ваш компьютер *очень* быстрый или функция таймера имеет низкое разрешение, возможно, придётся передать 100000 или даже 1000000, чтобы получить стабильные результаты.368369Когда получен стабильный результат, его можно использовать тремя способами:370371```python372import profile373374# 1. Применить вычисленное смещение ко всем экземплярам Profile, создаваемым в дальнейшем.375profile.Profile.bias = your_computed_bias376377# 2. Применить вычисленное смещение к конкретному экземпляру Profile.378pr = profile.Profile()379pr.bias = your_computed_bias380381# 3. Указать вычисленное смещение в конструкторе экземпляра.382pr = profile.Profile(bias=your_computed_bias)383```384385Если есть выбор, лучше выбрать меньшую константу – тогда результаты будут «реже» отображаться как отрицательные в статистике профилирования.386387## Расширения – создание более совершенных профайлеров388389Класс `Profile` обоих модулей, `profile` и `cProfile`, был написан так, чтобы можно было разрабатывать производные классы для расширения профилировщика. Подробности здесь не описываются, поскольку для успешного выполнения этого требуется экспертное понимание того, как работает класс `Profile` внутри. Внимательно изучите исходный код модуля, если хотите этим заняться.390391Если вы хотите только изменить способ определения текущего времени (например, чтобы принудительно использовать настенное время или затраченное процессорное время), передайте нужную функцию времени конструктору класса `Profile`:392393```python394pr = profile.Profile(your_time_func)395```396397Полученный профилировщик будет вызывать `your_time_func()`.398399**`profile.Profile`**400401`your_time_func()` должна возвращать одно число или список чисел, сумма которых равна текущему времени (как [`os.times()`](https://python-all.ru/3.0/library/os.html#os.times)). Если функция возвращает одно число или список из двух чисел, то будет использована особенно быстрая версия диспетчера.402403Имейте в виду, что следует откалибровать класс профилировщика для выбранной функции таймера. Для большинства машин таймер, возвращающий одно целое число, даёт наилучшие результаты с точки зрения низких накладных расходов при профилировании. ([`os.times()`](https://python-all.ru/3.0/library/os.html#os.times) *довольно* плох, так как возвращает кортеж чисел с плавающей точкой). Если вы хотите заменить таймер наиболее чистым способом, создайте производный класс и жёстко задайте заменяющий метод диспетчеризации, который наилучшим образом обрабатывает ваш вызов таймера, вместе с соответствующей константой калибровки.404405**`cProfile.Profile`**406407`your_time_func()` должна возвращать одно число. Если она возвращает целые числа, можно также вызвать конструктор класса со вторым аргументом, указывающим реальную длительность одной единицы времени. Например, если `your_integer_time_func()` возвращает время, измеренное в тысячных долях секунды, создайте экземпляр `Profile` следующим образом:408409```python410pr = profile.Profile(your_integer_time_func, 0.001)411```412413Поскольку класс `cProfile.Profile` невозможно откалибровать, пользовательские таймерные функции следует использовать с осторожностью и делать их максимально быстрыми. Для достижения наилучших результатов с пользовательским таймером может потребоваться встроить его непосредственно в исходный код на C внутреннего модуля `_lsprof`.414415Сноски416417| [\[1\]](https://python-all.ru/3.0/library/profile.html#id1) | Обновлено и преобразовано в LaTeX Гвидо ван Россумом. Дополнительно обновлено Армином Риго для включения документации нового модуля `cProfile` в Python 2.5. |418| --- | --- |419