10 промтов для оптимизации производительности кода: от профилирования до рефакторинга
Оптимизация производительности — это не «ранняя оптимизация», а способ избежать катастроф при росте нагрузки. Согласно исследованию SOASTA (2017), задержка в 100 мс снижает конверсии на 7%, а задержка в 500 мс — уже на 26% [источник: Google/SOASTA «The Need for Mobile Speed»]. При этом большинство разработчиков тратят часы на ручной анализ кода, хотя современные языковые модели способны взять на себя рутину: найти узкие места, предложить рефакторинг и даже сгенерировать профилирующие скрипты. Важно понимать: LLM — это не замена профайлеру и бенчмаркам, а ускоритель аналитики.
В этой подборке — 10 проверенных промтов, которые я использую в реальных проектах: от Python-микросервисов до фронтенд-бандлов. Каждый промт снабжён примером использования и ожидаемым результатом. Вы увидите, как с помощью правильно сформулированного запроса можно сэкономить часы работы и найти такие узкие места, которые вручную ищутся неделю.
Как правильно формулировать промты для оптимизации
Прежде чем перейти к подборке, запомните три правила:
- Давайте контекст. Указывайте язык, фреймворк, версию, ожидаемую нагрузку (RPS, размер данных). Модель должна понимать, в каких условиях работает код.
- Требуйте доказательства. Просите не просто совет, а объяснение, почему это ускорит код и какие компромиссы вы получите.
- Просите метрики. Хороший промт должен поощрять LLM приводить теоретические замеры или план эксперимента для проверки.
Теперь — к делу. Ниже 10 промтов, отсортированных по типу задачи: от CPU-профилирования до кэширования.
1. Анализ CPU-профиля и поиск горячих точек
Когда применять: вы уже получили cProfile-дамп или лог с медленными вызовами, но не можете понять, что именно жрёт процессор.
Промт:
У меня есть дамп cProfile (Python 3.11) для API-эндпоинта /get_orders. Обработка одного запроса занимает 2.3 секунды. Помоги проанализировать вывод и найти топ-5 узких мест. Выведи таблицу: функция, общее время, время на вызов, количество вызовов. Предложи, какой участок кода следует оптимизировать в первую очередь и почему. Вот данные:
[вставьте вывод cProfile]
Пример результата: LLM проанализирует таблицу и выделит, например, что функция process_items() вызывается 1000 раз и суммарно занимает 76% времени. Предложит заменить цикл на векторные операции NumPy или использовать functools.lru_cache — с оценкой ускорения.
Почему это работает: модель выделяет статистические аномалии, а не просто смотрит на вертикальную черту. Она учитывает совокупное время с учётом вложенных вызовов.
2. Оптимизация сложности алгоритма (Big-O)
Когда применять: вы видите, что код работает быстро на 100 элементах, но падает на миллионе. Промт помогает формализовать проблему и найти альтернативу.
Промт:
Оцени асимптотическую сложность этой функции (Python). Если сложность O(n^2) или выше, предложи альтернативный алгоритм и распиши, как улучшить до O(n log n). Дай пример переписанного кода и объясни, почему новая версия будет масштабироваться. Вот код:
def find_duplicates(items):
duplicates = []
for i in range(len(items)):
for j in range(i+1, len(items)):
if items[i] == items[j] and items[i] not in duplicates:
duplicates.append(items[i])
return duplicates
Пример результата: модель укажет на O(n^2), предложит использовать set или Counter, и приложит новый код: [x for x, cnt in Counter(items).items() if cnt > 1]. Это снизит сложность до O(n). Также она предупредит, что если порядок важен, нужно использовать dict.fromkeys().
3. Оптимизация SQL-запросов с помощью EXPLAIN
Когда применять: запросы к базе данных замедляются под нагрузкой. Промт помогает расшифровать EXPLAIN и выбрать правильную стратегию индексирования.
Промт:
У меня есть PostgreSQL 15 таблица orders (10M строк) с индексом по столбцу created_at. Запрос SELECT ... WHERE created_at BETWEEN '2025-01-01' AND '2025-06-01' ORDER BY created_at LIMIT 100 выполняется 500 мс. При этом EXPLAIN показывает Seq Scan вместо Index Scan. Почему так происходит? Предложи 3 способа ускорить запрос и объясни, какой из них лучше для этого случая. Выведи ответ в виде таблицы: способ, ожидаемый эффект, риски.
Пример результата: LLM объяснит, что Seq Scan может быть выбран оптимизатором из-за большого количества совпадающих строк (>5%). Предложит инвертировать условие, добавить составной индекс (created_at, id) и использовать FETCH FIRST 100 ROWS ONLY без ORDER BY на большой выборке.
| Способ | Ожидаемый эффект | Риски |
|---|---|---|
| Составной индекс | Сканирование по индексу | Дополнительное место |
| Уточнение statistics | Корректный план | Обновление таблиц |
| Партиционирование | Меньше данных | Миграция схемы |
4. Анализ использования памяти и поиск утечек
Когда применять: процессы медленно «раздуваются» и падают по OOM. Промт поможет интерпретировать вывод трассировщика памяти.
Промт:
Вот вывод tracemalloc для Python-демона, который обрабатывает вебхуки. Через 12 часов работы память достигает 4 ГБ и процесс убивается OOM-killer. Найди в выводе объекты, которые потенциально удерживаются ссылками, и объясни, как исправить. Данные:
[вставьте вывод tracemalloc]
Также посоветуй инструменты для профилирования памяти в production (например, memory-profiler или Pympler).
Пример результата: модель найдёт рост списков в глобальной переменной, предложит использовать weakref или очищать структуру после обработки. В ответе — паттерн для тестирования утечек с помощью gc.get_objects().
5. Оптимизация загрузки фронтенда (бандл и рендеринг)
Когда применять: Lighthouse в браузере показывает низкий Performance Score (ниже 60). Промт помогает разобрать отчёт и расставить приоритеты.
Промт:
У меня Next.js 14 проект, страница /list. Lighthouse (в режиме Incognito, Chrome 120) показывает: LCP 4.2s, CLS 0.15, TBT 800ms. Проанализируй потенциальные причины: 1) серверный рендеринг с длинным useEffect, 2) огромный JS-бандл (2.4 МБ), 3) отсутствие кэширования изображений. Предложи конкретные действия: что первым делом исправить, какие библиотеки удалить, как подключить next/image. Дай оценку улучшения для каждого пункта.
Пример результата: LLM предложит разбить бандл на чанки через dynamic import, заменить moment.js на date-fns, включить сжатие Brotli. Для LCP — использовать loading="lazy" и priority на первом экране. Оценка: LCP уменьшится до 2.1s, TBT — до 200ms.
6. Поиск проблем конкурентности и гонок данных
Когда применять: код работает быстро на одном потоке, но даёт сбои при многопоточности.
Промт:
Вот Go-функция, обрабатывающая запросы через горутины и общие map. Периодически panic: assignment to entry in nil map. Диагностируй проблему и предложи безопасную альтернативу. Учти, что нужно минимизировать блокировки. Код:
func process(requests []Req) {
m := make(map[string]Result)
var wg sync.WaitGroup
for _, r := range requests {
wg.Add(1)
go func() {
m[r.ID] = compute(r)
wg.Done()
}()
}
wg.Wait()
}
Пример результата: модель укажет на гонку данных, объяснит, что map не потокобезопасна, предложит sync.Map, мьютекс или каналы. Приведёт пример с каналами, где каждый воркер отправляет результат в общий канал.
7. Оптимизация асинхронного кода в Python (asyncio)
Когда применять: async-приложение выполняет запросы последовательно, хотя можно параллельно.
Промт:
Мой asyncio-скрипт делает 100 HTTP-запросов через httpx к разным API. Время выполнения — 15 секунд. Я использую await client.get() в цикле for. Ускори это, используя asyncio.gather или semaphore для ограничения конкуренции. Напиши код с учётом лимита 10 параллельных запросов. Также объясни разницу между gather и TaskGroup (Python 3.11).
Пример результата: LLM предложит asyncio.Semaphore(10) и gather, покажет разницу в обработке ошибок: gather (return_exceptions=True) vs TaskGroup (отменяет все при первой ошибке).
8. Автоматическое ревью кода на предмет производительности
Когда применять: нужно быстро прогнать большое количество изменений перед code review.
Промт:
Представь, что ты senior performance engineer. Вот пул-реквест с изменениями в Python-сервисе (FastAPI). Проанализируй код на предмет потенциальных проблем с производительностью: N+1 запросы к БД, тяжелые вычисления в циклах, неэффективные структуры данных, лишние копии объектов. Выдай список в формате: файл, строка, проблема, серьёзность (Critical/Major/Minor), рекомендуемое исправление. Код:
[вставьте diff]
Пример результата: модель найдёт, например, что в endpoint’е для списка заказов вызывается cursor.execute внутри цикла по пользователям — предложит JOIN или selectinload. Также обратит внимание на создание списка в цикле, которое можно заменить генератором.
9. Оптимизация ввода-вывода и пакетная обработка
Когда применять: приложение выполняет операции по одной записи в файл или СУБД, создавая сильную нагрузку на диск.
Промт:
Скрипт читает CSV на 10 ГБ и для каждой строки делает INSERT в MySQL. Скорость — 500 строк/с. Предложи стратегию пакетной вставки (bulk insert) и объясни, как влияет размер батча на скорость и память. Напиши пример на Python с executemany(), добавь использование tqdm для прогресса. Также предложи, как ускорить чтение через csv.DictReader вместо csv.reader.
Пример результата: модель покажет решение с executemany(..., batch_size=1000), обратит внимание на max_allowed_packet MySQL и скорость диска. Приведёт замеры: частота вставки вырастает с 500 до 5000 строк/с.
10. Анализ логов и трассировок для поиска медленных вызовов
Когда применять: у вас нет профайлера, но есть структурированные логи с временем выполнения.
Промт:
Вот фрагмент структурированного лога Nginx + Gunicorn. Видно, что некоторые запросы занимают более 3 секунд. Найди паттерн: какой эндпоинт самый медленный, в какой час пик, есть ли корреляция с размером тела запроса. Предложи, какие метрики добавить и куда посмотреть в первую очередь (БД, внешние API). Лог:
[вставьте логи в формате JSON]
Пример результата: LLM выделит эндпоинт /export, который зависит от внешнего API, и предложит добавить тайминги для каждого вызова, включить кэширование, а репорт собрать в фоновом режиме.
11. Использование кэширования для ускорения API
Когда применять: один и тот же тяжёлый запрос выполняется многократно с одинаковыми параметрами.
Промт:
У меня REST API на FastAPI с эндпоинтом /product/{id}, который делает 5 обращений к БД и вычисляет рейтинг. Нагрузка — 100 RPS, среднее время 300 мс. Предложи схему кэширования: in-memory (functools.lru_cache) vs Redis, с каким TTL, и как инвалидировать при обновлении продукта. Напиши пример декоратора для кэша и объясни, как учесть разные пользователи.
Пример результата: модель предложит Redis с TTL=60 секунд и инвалидацией через событие при обновлении. Покажет код кастомной обёртки для асинхронного кэша.
Заключение
Промты — это не магия: они не заменят вам perf, cProfile или Lighthouse. Но они экономят часы на синтезе информации и шаблонных решениях. Используйте подборку как отправную точку, адаптируйте под свой стек и не забудьте проверить результаты бенчмарками.
Если вы хотите углубиться в перформанс-инженерию, начните с документации профайлеров: cProfile для Python, perf для Linux, Chrome DevTools для фронтенда. Сохраните статью в закладки, и пусть ваш код работает быстро.
Комментарии