Баннер мобильный (3) Пройти тест

Профилирование Python-кода: что это и зачем нужно

Как сбор характеристик о программе помогает улучшить код

Разбор

27 мая 2025

Поделиться

Скопировано
Профилирование Python-кода: что это и зачем нужно

Содержание

    Чтобы оптимизировать программу, сделать ее быстрее и точнее, нужно понимать, как она устроена. Для этого применяют метод профилирования: собирают информацию о поведении программы и делают на ее основе выводы.

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

    Для чего нужно профилирование

    Представьте ситуацию: программа тормозит и выполняет простые действия очень долго. Код работает, но почему-то медленно. Понять, в чем причина, с первого взгляда не получается. Профилирование — метод, который поможет ее проанализировать.

    С помощью профилирования можно узнать:

    • о быстродействии программы — сколько времени у нее уходит на работу в целом и на конкретные действия;
    • об узких местах — bottleneck, или бутылочных горлышках, то есть таких участках кода, где программа работает медленнее всего;
    • о количестве вызовов каждой функции и о том, какие из них вызывают чаще всего — такие функции называют hot spots;
    • о затраченных ресурсах — сколько памяти, вычислительных мощностей процессора и других ресурсов тратит программа на работу.

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

    Каким бывает профилирование

    Способы профилирования кода отличаются друг от друга. Выделяют несколько видов в зависимости от того, что, когда и каким методом проверяют. 

    Статическое и динамическое. Статическое профилирование анализирует код программы, когда она не запущена. Динамическое проводится во время работы программы и отслеживает показатели в реальном времени.

    Ручное, статистическое или событийное. При ручном профилировании разработчик сам пишет код, который измеряет быстродействие программы. В двух других случаях он действует с помощью специальных инструментов — профилировщиков кода, или профайлеров (profilers). 

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

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

    Временное и пространственное. Первый оценивает временную сложность — сколько времени нужно программе, чтобы выполнить действия. Второй — пространственную сложность: сколько ресурсов потребляет код во время работы. Отдельно выделяют профилирование операций ввода-вывода: они могут быть довольно затратными по времени, так что их проверяют отдельно. А еще есть вычислительное профилирование: оно объединяет в себе все перечисленные виды.

    Инструменты для профилирования Python-кода

    Профилировать код можно с помощью нескольких инструментов. Разберем самые популярные из них — от простых функций, встроенных в Python, до специальных сторонних профилировщиков.

    Встроенные функции

    Простым ручным профилированием в Python можно заниматься без специальных профайлеров. Для этого пригодятся некоторые встроенные в язык инструменты:

    • time — модуль, который содержит функции, связанные с временем. Например, с его помощью можно отсчитывать количество времени от одного момента до другого;
    • sys — модуль, где содержатся функции для взаимодействия с интерпретатором Python. Он может выдавать информацию о размере того или иного объекта, количество ссылок на этот объект и другие параметры.

    Эти модули подойдут только для простейших действий. Для более сложного и подробного анализа лучше использовать более продвинутые инструменты.

    cProfile 

    Это встроенный в Python профайлер, написанный на языке C. Он может формировать отчеты о времени выполнения и затраченных ресурсах. Есть еще один модуль — profile: он делает то же самое, но написан на самом Python, поэтому работает чуть медленнее. Python cProfile — один из самых популярных инструментов для базового профилирования, но для некоторых задач его недостаточно. Например, он не показывает данные по отдельным строкам кода — только по функциям целиком.

    timeit

    Еще один встроенный модуль — он проще, чем cProfile, но тоже может измерять потраченное на работу кода время. При этом он отключает сборщик мусора, чтобы измерения были точнее и не искажались из-за фоновых процессов. Но timeit подходит только для небольших участков кода. Чтобы проанализировать большую программу, его недостаточно.

    line_profiler

    Это сторонний инструмент, фактически — обертка над cProfile. В нем, в отличие от встроенного модуля, можно смотреть время выполнения кода по строкам. Но на длинных программах он работает довольно медленно, поэтому его используют только для проверки небольших участков кода.

    memory_profiler

    Это инструмент для профилирования памяти в Python. Он отслеживает не время работы, а то, сколько памяти потратила та или иная программа при исполнении. Он также умеет выводить результаты для каждой строки кода, поэтому профилирование получается довольно подробным.

    py-spy

    Это сэмплирующий профилировщик — он несколько раз прерывает уже запущенную программу, чтобы считать ее данные. Это позволяет анализировать код в процессе выполнения и не слишком терять в скорости работы. В отличие от большинства сторонних профайлеров, py-spy написан не на Python или C, а на языке Rust. Он умеет просматривать исходные процессы и считывать их память напрямую.

    Yappi

    Название означает yet another Python profiler — то есть «еще один профилировщик для Python». Его удобно применять для анализа многопоточных приложений: он может профилировать каждый процесс по отдельности. Этот профайлер по умолчанию используется в среде программирования PyCharm.

    Функции Greenlet

    Вообще, Greenlet — это модуль для использования гринлетов, легковесных микропотоков, которыми можно управлять вручную. Но для гринлетов не подходят стандартные инструменты профилирования. Поэтому в модуле есть отдельные функции для трассировки и отслеживания кода с гринлетами. 

    iotop

    Это утилита, которая позволяет оценить использование диска — в частности, операции ввода-вывода. С ее помощью можно проверить, насколько часто программа записывает что-то на диск или читает с него, а также сколько времени это занимает. Работает она не только с Python-кодом — статистика выводится по всем процессам, которые запущены на компьютере.

    nethogs

    Еще одна полезная утилита мониторит использование сетевых ресурсов. Она проверяет, насколько часто та или иная программа обращается к сети и сколько времени тратит на обмен информацией. Как и iotop, она умеет проверять не только конкретную программу, а любой запущенный процесс — или все процессы отдельного пользователя.

    Вспомогательные инструменты

    Есть модули и библиотеки, которые не профилируют код сами, но помогают обработать и визуализировать результаты анализа. Вот что это за инструменты:

    • Statsmodels — библиотека для статистического моделирования. С ее помощью можно построить статистическую модель производительности кода, а за основу взять результаты профилирования;
    • gprof2dot визуализатор результатов профилирования, который представляет их в виде легко читаемой блок-схемы. Схему можно сохранить как картинку;
    • pycallgraph инструмент, который визуализирует структуру кода в виде графа. Он показывает, какие модули и функции используются в программе и как они связаны друг с другом;
    • snakeviz — интерактивный визуализатор для результатов профилирования с помощью cProfile. Он работает в браузере, его легко установить и использовать.

    Как эффективнее профилировать код

    Есть вещи, о которых нужно помнить во время профайлинга, чтобы выполнить его качественно. Так результаты будут объективными и полезными для дальнейшей оптимизации. Вот как стоит подходить к работе.

    Выбирать подходящий инструмент

    Для каждой задачи лучше подходит свой модуль. Например, для построчного профилирования стоит использовать line-profiler, а для подробного анализа на уровне функций — cProfile. Если программа многопоточная, лучше выбрать инструмент, который умеет анализировать потоки.

    Не оптимизировать код слишком рано

    Есть известная фраза, которую приписывают ученому Дональду Кнуту: «Преждевременная оптимизация — это корень всех бед». Сам Кнут говорил, что автор цитаты не он, но любил ее повторять. Считается, что правильнее сначала довести работу до конца, затем провести профилирование — и только потом оптимизировать, когда на руках уже есть вся информация о коде.

    Профилировать время каждого компонента по отдельности

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

    Приблизить условия работы программы к реальным

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

    Действовать постепенно

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

    Отслеживать, как меняется производительность

    После профилирования и оптимизации желательно сравнить программу с ее предыдущими версиями — смотреть, что именно изменилось и насколько выросла скорость работы.

    Коротко о профилировании кода на Python

    • Профилирование в программировании — это сбор информации о том, как работает код. Оно помогает найти узкие места и оптимизировать программу.
    • Профилирование бывает статическим и динамическим, а проводить его можно вручную или с использованием специальных инструментов — профилировщиков.
    • Профилировщики различаются характеристиками и способами использования. Одни подходят для статистического анализа, другие — для событийного. Есть специальные программы для работы с многопоточными программами.
    • Стандартный профилировщик в Python называется cProfile. Он анализирует код по функциям, но не умеет профилировать отдельные строки кода.
    • Чтобы профилирование было успешным, для него важно выбрать подходящий под задачу инструмент, действовать постепенно и не торопиться. После завершения работы сравнить результат с прошлыми версиями кода.

    Разбор

    Поделиться

    Скопировано
    0 комментариев
    Комментарии