Профилирование Python-кода: как найти, где тормозит ваш код
Python — отличный язык, пока всё работает быстро. Но однажды ваш код начинает тормозить, и вы сидите с кофе, глядя на for
-цикл, который работает "вечно".
И тут приходит время профилирования.
Профилирование — это как наблюдение за котом: вы хотите понять, куда он тратит время. Ест? Спит? Пялится в стену?
❓ Что такое профилирование?
Профилирование (profiling) — это процесс измерения производительности кода:
- Сколько времени тратится на выполнение?
- Какие функции вызываются чаще всего?
- Где программа "застревает"?
- Сколько памяти расходуется?
Профилирование отвечает на главный вопрос: "Где именно нужно оптимизировать?"
🐱 Пример: вы можете думать, что ваша программа тормозит из-за чтения файла… а на деле она 90% времени сортирует уже готовые данные.
📦 Виды профилирования
Профилирование бывает нескольких видов:
1. По времени выполнения
Отвечает на вопрос: что работает дольше всего?
В этом помогают cProfile
, line_profiler
, timeit
.
2. По потреблению памяти
Где создаются большие объекты? Есть ли утечки?
Инструменты: memory_profiler
, objgraph
, tracemalloc
.
3. По частоте вызовов
Какие функции вызываются слишком часто? Иногда частый вызов простой функции может сильно замедлять программу.
4. По уровню строки
Какие конкретные строки кода тормозят?
Ответ даёт line_profiler
.
5. Сэмплирующее профилирование
Инструмент "смотрит" в случайный момент времени и делает срез. Работает быстрее, но не даёт 100% точности. Используется в визуальных профайлерах типа SnakeViz, Py-Spy.
🧰 Основные инструменты профилирования в Python
1. cProfile
— встроенный профилировщик
Это стандартный инструмент, встроенный в Python. Используется так:
python -m cProfile my_script.py
import cProfile def main(): # ваш код pass cProfile.run('main()')
Результат: список функций, их вызовы и общее время выполнения, например:
5 function calls in 0.000 seconds Ordered by: cumulative time ncalls tottime percall cumtime percall filename:lineno(function) 1 0.000 0.000 0.000 0.000 {built-in method builtins.exec} 1 0.000 0.000 0.000 0.000 test.py:1(<module>) 1 0.000 0.000 0.000 0.000 test.py:1(main) 1 0.000 0.000 0.000 0.000 {built-in method builtins.print} 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
📊 Как читать результаты?
Вот на что стоит обращать внимание:
tottime Время, потраченное только в этой функции cumtime Время, включая вызовы вложенных функций
percall Среднее время за вызов
Ищите функции с большим cumtime
— они тормозят больше всего.
2. pstats
и сортировка результатов
Если хочется увидеть, где конкретно тормозит:
import cProfile import pstats profiler = cProfile.Profile() profiler.enable() # код main() profiler.disable() stats = pstats.Stats(profiler).sort_stats('cumtime') stats.print_stats(10) # топ-10 самых затратных функций
📌 cumtime
— это суммарное время на функцию и всё, что она вызывает.
3. line_profiler
— построчный анализ
pip install line_profiler
Используется с декоратором @profile
:
@profile def slow_function(): result = 0 for i in range(10000): result += i ** 2 return result
kernprof -l my_script.py python -m line_profiler my_script.py.lprof
🐱 Это как если бы вы поставили камеру над каждой строчкой кода и следили, где кот задерживается дольше всего.
4. memory_profiler
— куда уходит память
Похож на line_profiler
, но для RAM:
pip install memory_profiler
from memory_profiler import profile @profile def heavy_func(): a = [x for x in range(1000000)] return a
python -m memory_profiler my_script.py
5. timeit
— для измерения мелочей
Если вы хотите просто узнать, какая конструкция быстрее:
import timeit print(timeit.timeit("sum(range(100))", number=10000))
Полезно для микробенчмарков — быстро сравнить map()
против for
.
🔍 Советы по профилированию
- Не оптимизируй вслепую. Сначала замерь, потом думай.
- Фокус на "узкие места" — 10% кода может тратить 90% времени.
- Сравни до и после. Сделал оптимизацию? Проверь, стала ли она лучше.
- Профилируй настоящие сценарии. Тестовые данные часто обманывают.
- Учитывай сторонние библиотеки. Иногда
pandas
тормозит больше, чем ваш код.
🐾 Кошачий факт
Профилирование — это как установка камеры на кухне: вы думаете, что корм уходит за минуту, а оказывается — кот сидит и смотрит на миску 40 секунд, а потом ест за 3. Аналогично и с функциями: одна строчка может тормозить всё приложение.
✅ Вывод
Профилирование — это не про оптимизацию ради цифр, а про понимание, куда действительно уходит время и ресурсы.
Не гадайте — замеряйте. А уже потом думайте, где заменить кота… или append()
на генератор.