Профилирование 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() на генератор.