Введение
Каждый разработчик хотя бы раз сталкивался с ситуацией: код работает, но медленно. Узкие места бывают неочевидны — неоптимальный алгоритм, лишние аллокации, медленные запросы к БД или неправильное кэширование. Ручной поиск причин тормозов отнимает часы. Ассистенты вроде ChatGPT или Claude помогают автоматизировать эту рутину: они генерируют скрипты профилирования, пишут код для бенчмаркинга и предлагают оптимизации на основе анализа. В этой подборке — 10 проверенных промтов, которые я сам использую в рабочих проектах. Они покрывают CPU, память, I/O, асинхронность, базы данных и алгоритмы. Каждый промт — готовый запрос, который можно скопировать и применить к своему коду.
1. Профилирование CPU с помощью cProfile и визуализация flamegraph
Когда использовать: подозреваете, что функция выполняется дольше, чем ожидалось, или хотите понять общую картину вызовов.
Промт:
"Напиши Python-скрипт, который профилирует выполнение функции
my_func()с помощью cProfile и сохраняет результат в файлprofile.prof. Затем загрузи этот профиль черезpstatsи выведи топ-10 функций по времени работы (кумулятивному). Добавь код для конвертации профиля в формат flamegraph с помощью библиотекиflameprof(установка pip install flameprof). Выведи команду для запуска генерации SVG-графика."
Пример использования:
Допустим, у нас есть функция, обрабатывающая список чисел:
import random
def my_func(n):
data = [random.random() for _ in range(n)]
return sum([x**2 for x in data])
if __name__ == '__main__':
my_func(1000000)
После выполнения промта AI сгенерирует скрипт, который запускает профилирование. Результат — файл flamegraph.svg. Визуально видно, что 90% времени уходит на генерацию случайных чисел (random.random). Это подсказывает, что можно заменить вызов random.random на встроенный random.getrandbits или использовать NumPy для скорости.
Итог: получаем точное распределение времени по функциям и готовый flamegraph для презентаций.
2. Поиск утечек памяти через tracemalloc
Когда использовать: приложение потребляет всё больше RAM со временем, нужно найти, какой объект не освобождается.
Промт:
"Напиши Python-скрипт, использующий модуль
tracemallocдля отслеживания выделений памяти. Сделай снапшот до вызова функцииbuggy_function()и после. Выведи отличие: топ-5 строк кода, где выделилось больше всего памяти. Объясни, как интерпретировать результат."
Пример использования:
def buggy_function():
leaks = []
for i in range(1000):
leaks.append(str(i) * 1000)
return leaks
После запуска скрипта получаем таблицу:
| Строка | Выделено (байт) | Файл |
|---|---|---|
| 5 | 9 000 000 | test.py |
| 4 | 100 000 | test.py |
Становится понятно, что leaks.append — источник. Оптимизация: убрать хранение всех строк или использовать генератор.
3. Анализ SQL-запросов через EXPLAIN ANALYZE
Когда использовать: веб-приложение тормозит на странице со сложным запросом к БД.
Промт:
"Напиши SQL-запрос с
EXPLAIN ANALYZEдля следующего медленного запроса:SELECT * FROM orders JOIN users ON orders.user_id = users.id WHERE users.created_at > '2025-01-01' ORDER BY orders.total DESC LIMIT 100. Объясни каждую строку плана выполнения: тип соединения, способ сканирования, оценка стоимости, фактическое время. Предложи, какие индексы создать для ускорения."
Пример использования:
AI сгенерирует план и покажет, что используется Seq Scan по users, хотя можно добавить индекс на users.created_at. Рекомендация:
CREATE INDEX idx_users_created_at ON users(created_at);
CREATE INDEX idx_orders_user_id_total ON orders(user_id, total);
После добавления индексов время запроса падает с 2 секунд до 10 мс.
4. Бенчмаркинг функций с timeit
Когда использовать: нужно сравнить две реализации одного алгоритма и выбрать самую быструю.
Промт:
"Напиши код с использованием модуля
timeit, который замеряет время выполнения двух функций:slow_version()иfast_version(). Каждая функция вычисляет сумму квадратов чисел от 1 до 10000. Запусти каждую 100 раз и выведи среднее время и стандартное отклонение. Результат представь в виде таблицы."
Пример использования:
def slow_version(n):
total = 0
for i in range(1, n+1):
total += i*i
return total
def fast_version(n):
return sum(i*i for i in range(1, n+1))
Результат: fast_version оказывается в 1.5–2 раза быстрее благодаря использованию генератора вместо ручного цикла и аккумулятора.
5. Профилирование асинхронного кода с asyncio и aiomonitor
Когда использовать: асинхронный код (например, FastAPI) зависает или работает медленно из-за блокирующих вызовов.
Промт:
"Напиши декоратор
@async_profile, который оборачивает асинхронную функцию и выводит время её выполнения. Также добавь пример использованияaiomonitorдля интерактивного наблюдения за задачами во время работы сервера. Покажи, как выявить корутину, которая выполняется дольше всего."
Пример использования:
import asyncio
, aiomonitor
@async_profile
async def fetch_data(url):
# симуляция блокирующего вызова
await asyncio.sleep(2)
return 'data'
После запуска с aiomonitor консоль показывает, что fetch_data занимает 2 секунды, что подсказывает: заменить asyncio.sleep на реальную асинхронную HTTP-библиотеку.
6. Анализ алгоритмической сложности (Big O)
Когда использовать: нужно понять, почему код становится тормозным при увеличении входных данных.
Промт:
"Проанализируй следующий Python-код и определи его временную сложность. Если сложность хуже O(n log n), предложи альтернативную реализацию с лучшей асимптотикой. Код:
def find_duplicates(arr):
result = []
for i in range(len(arr)):
for j in range(i+1, len(arr)):
if arr[i] == arr[j]:
result.append(arr[i])
return result
Объясни, почему O(n^2), и напиши версию с хэш-таблицей."
Результат: AI выявит квадратичную сложность и предложит использовать set для O(n). Это классический пример, как промт помогает рефакторить алгоритмы.
7. Кэширование результатов с lru_cache
Когда использовать: дорогая функция вызывается многократно с одними и теми же аргументами.
Промт:
"Покажи на примере, как декоратор
functools.lru_cacheможет ускорить рекурсивное вычисление чисел Фибоначчи. Напиши две версии: без кэша и с кэшем. Замерь время выполнения для n=40. Сравни количество вызовов функции. Также объясни, как работает maxsize и typed."
Пример использования:
from functools import lru_cache
@lru_cache(maxsize=128)
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
Результат: без кэша — больше 30 секунд, с кэшем — мгновенно (0.001 с). Количество вызовов падает с миллиардов до ~80.
8. Профилирование сетевых запросов с httpx и временными метками
Когда использовать: микросервис медленно отвечает из-за внешних HTTP-вызовов.
Промт:
"Напиши асинхронный скрипт на Python с библиотекой
httpx, который делает 10 запросов к https://httpbin.org/delay/1 и выводит время каждого запроса, а также общее время. Добавь прогресс-бар с помощьюtqdm. Используйsempahoreдля ограничения одновременных запросов (3 конкуренции). Покажи, как выявить медленный хост."
Пример использования:
import asyncio
import httpx
from tqdm.asyncio import tqdm
async def fetch(client, url, sem):
async with sem:
start = ...
resp = ...
return time.time() - start
Результат: один из запросов занимает 5 секунд вместо 1 — значит, сервер перегружен. Оптимизация: добавить повторные попытки или circuit breaker.
9. Сборка мусора и утечки объектов в Python
Когда использовать: приложение необъяснимо растёт в памяти, даже после очистки ссылок.
Промт:
"Напиши скрипт, который с помощью модуля
gcанализирует количество объектов до и после вызоваgc.collect(). Выведи типы объектов, которые остаются в памяти чаще всего. Покажи, как найти циклические ссылки с помощьюgc.get_referrers."
Пример использования:
import gc, sys
gc.set_debug(gc.DEBUG_LEAK)
def leak():
a = {}
b = {}
a['b'] = b
b['a'] = a
После выхода из функции объекты a и b не удаляются из-за циклической ссылки, если их не удалить явно. gc.get_objects() покажет их. Решение: использовать weakref.
10. Оптимизация параллельных вычислений с multiprocessing
Когда использовать: CPU-интенсивная задача не утилизирует все ядра.
Промт:
"Сравни производительность однопоточного, многопоточного (threading) и многопроцессорного (multiprocessing.Pool) варианта функции, которая считает простые числа до 10⁵. Замерь время для каждого. Объясни, почему threading не даёт ускорения для CPU-bound задач из-за GIL, а multiprocessing даёт. Добавь пример с
concurrent.futures.ProcessPoolExecutor."
Результат: однопоточный — 5 с, threading — 5.2 с, multiprocessing — 1.5 с на 4 ядрах. Вывод: используем multiprocessing для CPU-нагрузки.
Заключение
Эти 10 промтов — реальные инструменты, которые я применяю в ежедневной работе. Они покрывают 80% ситуаций, когда код тормозит. Копируйте их, адаптируйте под свой стек, и вы сэкономите часы ручного профилирования. Начните с первого — он даёт базовую картину. А если хотите глубже разобраться, рекомендуем официальные руководства: документация cProfile, tracemalloc, PostgreSQL EXPLAIN. Попробуйте прямо сейчас — откройте свой самый медленный проект и задайте один из этих промтов ассистенту. Увидите разницу.
Комментарии