Способы профилирования Python-кода (cProfile, py-spy, memory_profiler)?

Для профилирования производительности Python-кода используют разные инструменты: cProfile и pstats для встроенного CPU‑профилирования, внешние сэмплирующие профайлеры вроде py-spy для низкого overhead’а и анализа продакшена, а также инструменты для памяти (memory_profiler, tracemalloc) для поиска утечек и «тяжёлых» объектов.
Подробный ответ

Senior‑ответ важен не перечнем инструментов, а пониманием, когда к какому подходу тянуться.

CPU-профилирование: cProfile + pstats

cProfile — встроенный детерминированный профилировщик CPU:

  • инструментирует каждый вызов функции, считает общее и собственное время;

  • даёт подробный call graph, но вносит заметный overhead;

  • отлично подходит для локального анализа, бенчей и одноразовых исследований.

import cProfile, pstats

pr = cProfile.Profile()
pr.enable()
# ... код для профилирования ...
pr.disable()
stats = pstats.Stats(pr)
stats.sort_stats("cumulative").print_stats(20)

Часто вывод импортируют в инструменты визуализации (snakeviz, gprof2dot + Graphviz) для удобного анализа.

Сэмплирующие профайлеры: py-spy и аналоги

py-spy — внешний сэмплирующий профилировщик:

  • подключается к уже запущенному процессу, не требует изменения кода;

  • регулярно «снимает стек» (sampling), строит flamegraph и статистику по функциям;

  • имеет куда меньший overhead и подходит для продакшена (осторожно, но реально применимо);

  • умеет работать с многопоточными/async‑приложениями.

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

Память: memory_profiler, tracemalloc, objgraph

  • memory_profiler — измеряет использование памяти по строкам/функциям; часто используется через декоратор @profile или командную утилиту; позволяет увидеть, какие участки кода дают рост RSS процесса.

  • tracemalloc (стандартная библиотека) отслеживает выделения памяти в Python‑объектах, даёт срезы по top‑allocations, умеет сравнивать снимки до/после, помогает в поиске утечек и неожиданных аллокаций.

  • objgraph и подобные библиотеки полезны для анализа графа объектов: какие типы растут, какие объекты держат ссылки на другие.

Практический workflow

Типичный подход senior‑разработчика:

  • сначала — высокоуровневые метрики (APM, метрики latency/CPU/RSS), чтобы понять, есть ли вообще проблема;

  • для CPU — локально cProfile на репрезентативном нагрузочном сценарии, а если нужно — py-spy или аналог на staging/production для уточнения «горячих» функций;

  • для памяти — tracemalloc/memory_profiler на подозрительных путях, сравнение снимков, поиск мест, где количество объектов растёт и не падает.

Формулировка для собеседования

Для профилирования CPU я обычно начинаю с cProfile + pstats локально, а при необходимости использую сэмплирующий профайлер вроде py-spy, который можно подключить даже к живому процессу и посмотреть flamegraph с меньшим overhead’ом. Для памяти — memory_profiler и tracemalloc, иногда с objgraph, чтобы увидеть, какие объекты растут. Дальше уже принимаю архитектурные решения: менять алгоритм, структуру данных, точки кеширования и т.п.

Оцени свой прогресс

Честно оцени своё понимание этого вопроса, чтобы мы могли построить твой учебный трек максимально эффективно.
Читать в блоге