10 промтов для оптимизации производительности кода: от профилирования до рефакторинга

10 промтов для оптимизации производительности кода: от профилирования до рефакторинга

Оптимизация производительности — это не «ранняя оптимизация», а способ избежать катастроф при росте нагрузки. Согласно исследованию SOASTA (2017), задержка в 100 мс снижает конверсии на 7%, а задержка в 500 мс — уже на 26% [источник: Google/SOASTA «The Need for Mobile Speed»]. При этом большинство разработчиков тратят часы на ручной анализ кода, хотя современные языковые модели способны взять на себя рутину: найти узкие места, предложить рефакторинг и даже сгенерировать профилирующие скрипты. Важно понимать: LLM — это не замена профайлеру и бенчмаркам, а ускоритель аналитики.

В этой подборке — 10 проверенных промтов, которые я использую в реальных проектах: от Python-микросервисов до фронтенд-бандлов. Каждый промт снабжён примером использования и ожидаемым результатом. Вы увидите, как с помощью правильно сформулированного запроса можно сэкономить часы работы и найти такие узкие места, которые вручную ищутся неделю.

Как правильно формулировать промты для оптимизации

Прежде чем перейти к подборке, запомните три правила:

  1. Давайте контекст. Указывайте язык, фреймворк, версию, ожидаемую нагрузку (RPS, размер данных). Модель должна понимать, в каких условиях работает код.
  2. Требуйте доказательства. Просите не просто совет, а объяснение, почему это ускорит код и какие компромиссы вы получите.
  3. Просите метрики. Хороший промт должен поощрять 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 для фронтенда. Сохраните статью в закладки, и пусть ваш код работает быстро.

← Все статьи

Комментарии

Читайте также