> **Источник:** https://python-all.ru/3.16/library/profiling.tracing.html
>
> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.

---

# `profiling.tracing` – Детерминированный профилировщик

Добавлено в версии 3.15.

**Исходный код:** [Lib/profiling/tracing/](https://python-all.ru/src/main/Lib/profiling/tracing)

---

Модуль `profiling.tracing` обеспечивает детерминированное профилирование программ на Python. Он отслеживает каждый вызов функции, возврат из функции и событие исключения, записывая точное время для каждого. Такой подход даёт точные счётчики вызовов и полную видимость выполнения программы, что делает его идеальным для разработки и тестирования.

> **Примечание**
>
> Этот модуль также доступен как `cProfile` для обратной совместимости. Имя `cProfile` будет продолжать работать во всех будущих версиях Python. Используйте тот стиль импорта, который подходит вашему коду:
>
> ```python
> # Рекомендуемый (новый стиль)
> import profiling.tracing
> profiling.tracing.run('my_function()')
>
> # Также работает (обратная совместимость)
> import cProfile
> cProfile.run('my_function()')
> ```

## Что такое детерминированное профилирование?

*Детерминированное профилирование* фиксирует каждый вызов функции, возврат из функции и событие исключения во время выполнения программы. Профилировщик измеряет точные временные интервалы между этими событиями, предоставляя точную статистику о том, как программа ведёт себя.

В отличие от [статистического профилирования](https://python-all.ru/3.16/library/profiling.sampling.html#profiling-sampling), которое периодически опрашивает стек вызовов для оценки затрат времени, детерминированное профилирование записывает каждое событие. Это означает, что вы получаете точные счётчики вызова, а не статистические приближения. Оборотная сторона в том, что инструментирование каждого события вносит накладные расходы, которые могут замедлить выполнение программы.

Интерпретируемая природа Python делает детерминированное профилирование практичным. Интерпретатор уже диспетчеризует события для вызовов и возвратов функций, поэтому профилировщик может подключиться к этому механизму без необходимости изменения кода. Накладные расходы обычно невелики по сравнению с внутренними затратами на интерпретацию, что делает детерминированное профилирование подходящим для большинства рабочих процессов разработки.

Детерминированное профилирование помогает ответить на такие вопросы, как:

- Сколько раз была вызвана эта функция?
- Каков полный граф вызовов моей программы?
- Какие функции вызываются конкретной функцией?
- Происходят ли неожиданные вызовы функций?

Статистика счётчиков вызовов может выявить ошибки (неожиданные значения) и возможности для встраивания (высокие счётчики вызовов). Статистика внутреннего времени показывает «горячие циклы», требующие оптимизации. Статистика кумулятивного времени помогает выявить алгоритмическую неэффективность. Обработка кумулятивного времени в этом профилировщике позволяет напрямую сравнивать рекурсивные и итеративные реализации.

## Интерфейс командной строки

Модуль `profiling.tracing` можно вызвать как сценарий для профилирования другого сценария или модуля:

```console
python -m profiling.tracing [-o output_file] [-s sort_order] (-m module | script.py)
```

Это запускает указанный сценарий или модуль под профилировщиком и выводит результаты в стандартный вывод (или сохраняет их в файл).

#### `-o <output_file>`

Записывает результаты профилирования в файл, а не в стандартный вывод. Выходной файл может быть прочитан модулем [`pstats`](https://python-all.ru/3.16/library/pstats.html#module-pstats) для последующего анализа.

#### `-s <sort_order>`

Сортирует вывод по указанному ключу. Принимает любой из ключей сортировки, распознаваемых [`pstats.Stats.sort_stats()`](https://python-all.ru/3.16/library/pstats.html#pstats.Stats.sort_stats), таких как `cumulative`, `time`, `calls` или `name`. Этот параметр применяется только если [`-o`](https://python-all.ru/3.16/library/profiling.tracing.html#cmdoption-profiling.tracing-o) не указан.

#### `-m <module>`

Профилирует модуль вместо сценария. Модуль находится с помощью стандартного механизма импорта.

Добавлено в версии 3.7: Параметр `-m` для `cProfile`.

Добавлено в версии 3.8: Параметр `-m` для [`profile`](https://python-all.ru/3.16/library/profile.html#module-profile).

## Примеры программного использования

Для более тонкого управления профилированием используйте функции и классы модуля напрямую.

### Основное профилирование

Самый простой подход – использовать функцию `run()`:

```python
import profiling.tracing
profiling.tracing.run('my_function()')
```

Это профилирует переданную строку кода и выводит сводку в стандартный вывод. Чтобы сохранить результаты для последующего анализа:

```python
profiling.tracing.run('my_function()', 'output.prof')
```

### Использование `Profile` класса

Класс `Profile` обеспечивает детальный контроль:

```python
import profiling.tracing
import pstats
from io import StringIO

pr = profiling.tracing.Profile()
pr.enable()
# ... код для профилирования ...
pr.disable()

# Вывести результаты
s = StringIO()
ps = pstats.Stats(pr, stream=s).sort_stats(pstats.SortKey.CUMULATIVE)
ps.print_stats()
print(s.getvalue())
```

Класс `Profile` также работает как менеджер контекста:

```python
import profiling.tracing

with profiling.tracing.Profile() as pr:
    # ... код для профилирования ...

pr.print_stats()
```

## Справочник модуля

#### `profiling.tracing.run(command, filename=None, sort=-1)`

Профилирует выполнение команды и выводит или сохраняет результаты.

Эта функция выполняет строку *command* с помощью [`exec()`](https://python-all.ru/3.16/library/functions.html#exec) в пространстве имён модуля `__main__`:

```python
exec(command, __main__.__dict__, __main__.__dict__)
```

Если *filename* не указан, функция создаёт экземпляр [`pstats.Stats`](https://python-all.ru/3.16/library/pstats.html#pstats.Stats) и выводит сводку в стандартный вывод. Если *filename* указан, необработанные данные профиля сохраняются в этот файл для последующего анализа с помощью [`pstats`](https://python-all.ru/3.16/library/pstats.html#module-pstats).

Аргумент *sort* задаёт порядок сортировки для выводимых данных, принимая любое значение, распознаваемое [`pstats.Stats.sort_stats()`](https://python-all.ru/3.16/library/pstats.html#pstats.Stats.sort_stats).

#### `profiling.tracing.runctx(command, globals, locals, filename=None, sort=-1)`

Профилирует выполнение команды с явными пространствами имён.

Как [`run()`](https://python-all.ru/3.16/library/profiling.tracing.html#profiling.tracing.run), но выполняет команду с указанными отображениями *globals* и *locals* вместо использования пространства имён модуля `__main__`:

```python
exec(command, globals, locals)
```

#### `class profiling.tracing.Profile(timer=None, timeunit=0.0, subcalls=True, builtins=True)`

Объект профилировщика, собирающий статистику выполнения.

Необязательный аргумент *timer* задаёт пользовательскую функцию замера времени. Если он не указан, профилировщик использует таймер по умолчанию, подходящий для платформы. При передаче пользовательского таймера он должен возвращать одно число, представляющее текущее время. Если таймер возвращает целые числа, используйте *timeunit*, чтобы указать длительность одной единицы времени (например, `0.001` для миллисекунд).

Аргумент *subcalls* управляет тем, отслеживает ли профилировщик отношения вызовов между функциями. Аргумент *builtins* управляет тем, профилируются ли встроенные функции.

Изменено в версии 3.8: Добавлена поддержка контекстного менеджера.

#### `enable()`

Начинает сбор данных профилирования.

#### `disable()`

Прекращает сбор данных профилирования.

#### `create_stats()`

Прекращает сбор данных и сохраняет результаты внутри как текущий профиль.

#### `print_stats(sort=-1)`

Создаёт объект [`pstats.Stats`](https://python-all.ru/3.16/library/pstats.html#pstats.Stats) из текущего профиля и выводит результаты в стандартный вывод.

Аргумент *sort* задаёт порядок сортировки. Он принимает один ключ или кортеж ключей для многоуровневой сортировки, используя те же значения, что и [`pstats.Stats.sort_stats()`](https://python-all.ru/3.16/library/pstats.html#pstats.Stats.sort_stats).

Добавлено в версии 3.13: Поддержка кортежа ключей сортировки.

#### `dump_stats(filename)`

Записывает текущие данные профиля в *filename*. Файл может быть прочитан с помощью [`pstats.Stats`](https://python-all.ru/3.16/library/pstats.html#pstats.Stats) для последующего анализа.

#### `run(cmd)`

Профилирует строку команды с помощью [`exec()`](https://python-all.ru/3.16/library/functions.html#exec).

#### `runctx(cmd, globals, locals)`

Профилирует строку команды с помощью [`exec()`](https://python-all.ru/3.16/library/functions.html#exec) с указанными пространствами имён.

#### `runcall(func, /, *args, **kwargs)`

Профилирует вызов функции. Возвращает то, что возвращает *func*:

```python
result = pr.runcall(my_function, arg1, arg2, keyword=value)
```

> **Примечание**
>
> Для профилирования необходимо, чтобы профилируемый код завершился нормально. Если интерпретатор завершится (например, через [`sys.exit()`](https://python-all.ru/3.16/library/sys.html#sys.exit)) во время профилирования, результаты получены не будут.

## Использование пользовательского таймера

Класс [`Profile`](https://python-all.ru/3.16/library/profiling.tracing.html#profiling.tracing.Profile) принимает пользовательскую функцию таймера, позволяя измерять различные аспекты выполнения, такие как реальное время (wall-clock time) или процессорное время. Передайте функцию таймера в конструктор:

```python
pr = profiling.tracing.Profile(my_timer_function)
```

Функция таймера должна возвращать одно число, представляющее текущее время. Если она возвращает целые числа, также укажите *timeunit*, чтобы указать продолжительность одной единицы:

```python
# Таймер возвращает время в миллисекундах
pr = profiling.tracing.Profile(my_ms_timer, 0.001)
```

Для наилучшей производительности функция таймера должна быть как можно быстрее. Профилировщик вызывает её часто, поэтому накладные расходы таймера напрямую влияют на накладные расходы профилирования.

Модуль [`time`](https://python-all.ru/3.16/library/time.html#module-time) предоставляет несколько функций, подходящих для использования в качестве пользовательских таймеров:

- [`time.perf_counter()`](https://python-all.ru/3.16/library/time.html#time.perf_counter) для астрономического времени (высокое разрешение)
- [`time.process_time()`](https://python-all.ru/3.16/library/time.html#time.process_time) для процессорного времени (без учёта сна)
- [`time.monotonic()`](https://python-all.ru/3.16/library/time.html#time.monotonic) для монотонного времени

## Ограничения

Детерминированное профилирование имеет внутренние ограничения, связанные с точностью измерения времени.

Базовый таймер обычно имеет разрешение около одной миллисекунды. Измерения не могут быть точнее этого разрешения. При достаточном количестве измерений ошибки синхронизации обычно усредняются, но отдельные измерения могут быть неточными.

Существует также задержка между моментом возникновения события и моментом захвата временной метки профилировщиком. Аналогично, после чтения временной метки есть задержка, прежде чем пользовательский код возобновит выполнение. Часто вызываемые функции накапливают эту задержку, из-за чего они могут казаться медленнее, чем на самом деле. Эта ошибка обычно составляет менее одного тика часов на вызов, но может стать значительной для функций, вызываемых многократно.

Модуль `profiling.tracing` (и его псевдоним `cProfile`) реализован как расширение на C с низкими накладными расходами, поэтому эти проблемы синхронизации менее заметны по сравнению с устаревшим чисто Python-модулем [`profile`](https://python-all.ru/3.16/library/profile.html#module-profile).

> **См. также**
>
> **[`profiling`](https://python-all.ru/3.16/library/profiling.html#module-profiling)**
>
> Обзор инструментов профилирования Python и рекомендации по выбору профилировщика.
>
> **[`profiling.sampling`](https://python-all.ru/3.16/library/profiling.sampling.html#module-profiling.sampling)**
>
> Статистический профилировщик с выборкой для использования в production.
>
> **[`pstats`](https://python-all.ru/3.16/library/pstats.html#module-pstats)**
>
> Анализ статистики и форматирование данных профилирования.
>
> **[`profile`](https://python-all.ru/3.16/library/profile.html#module-profile)**
>
> Устаревший чисто Python-профилировщик (включает документацию по калибровке).
