Как профилировать производительность кода (cProfile)?python-25

Профилирование (profiling) - это процесс анализа времени выполнения и использования ресурсов различными частями программы. В Python стандартная библиотека предоставляет мощный инструмент cProfile для этого.

Основы cProfile

cProfile - это встроенный модуль Python, который предоставляет детальную статистику о времени выполнения каждой функции в вашем коде. Вот как его использовать:

import cProfile

def example_function(n):
    total = 0
    for i in range(n):
        total += i
    return total

# Профилируем функцию
profiler = cProfile.Profile()
profiler.enable()  # Начинаем сбор статистики

example_function(1000000)

profiler.disable()  # Останавливаем сбор статистики
profiler.print_stats(sort='cumtime')  # Выводим результаты, сортируя по общему времени

Ключевые параметры вывода

Когда вы вызываете print_stats(), вы получаете таблицу с такими столбцами:

  • ncalls: количество вызовов функции
  • tottime: общее время, проведенное в функции (исключая время вложенных вызовов)
  • percall: время на один вызов (tottime/ncalls)
  • cumtime: кумулятивное время, включая вложенные вызовы
  • filename:lineno(function): информация о функции

Практический пример

Рассмотрим более сложный пример с несколькими функциями:

import cProfile
import time

def fast_function():
    return sum(range(1000))

def slow_function():
    time.sleep(0.1)
    return 42

def main():
    result = 0
    for _ in range(100):
        result += fast_function()
        result += slow_function()
    return result

if __name__ == "__main__":
    cProfile.run('main()', sort='tottime')

Анализ результатов

При анализе обратите внимание на:

  1. Функции с наибольшим cumtime - "горячие точки" (hot spots)
  2. Функции с большим количеством вызовов (ncalls)
  3. Неожиданно медленные простые функции

Альтернативные способы профилирования

  1. Декоратор для профилирования:
import cProfile
import pstats
from functools import wraps

def profile_deco(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        profiler = cProfile.Profile()
        result = profiler.runcall(func, *args, **kwargs)
        stats = pstats.Stats(profiler)
        stats.strip_dirs().sort_stats('cumtime').print_stats(10)
        return result
    return wrapper

@profile_deco
def my_function():
    # ваш код
  1. Сохранение результатов в файл:
profiler = cProfile.Profile()
profiler.enable()
# ваш код
profiler.disable()
profiler.dump_stats('profile_results.prof')

Визуализация результатов

Для лучшего понимания можно использовать:

  • snakeviz: pip install snakeviz затем snakeviz profile_results.prof
  • pyprof2calltree с KCacheGrind

Рекомендации

  1. Профилируйте только критичные участки кода
  2. Проводите тесты на реалистичных данных
  3. Сравнивайте изменения до и после оптимизации
  4. Не оптимизируйте преждевременно - сначала найдите реальные узкие места

Резюмируем

cProfile - мощный инструмент стандартной библиотеки Python для анализа производительности. Он помогает находить узкие места в коде, предоставляя детальную статистику о времени выполнения функций. Для лучшего понимания результатов используйте сортировку по разным параметрам и визуализацию с помощью дополнительных инструментов.