Введение
Каждый разработчик сталкивался с ситуацией, когда код работает медленно, а причина неясна. Оптимизация производительности — это не гадание, а системный процесс, который начинается с профилирования и заканчивается рефакторингом. В этой подборке — 12 проверенных промтов, которые я использую ежедневно для поиска узких мест и ускорения кода. Они помогут вам быстрее находить проблемы и принимать обоснованные решения, опираясь на данные, а не на интуицию. Все примеры основаны на реальных кейсах из проектов на Python, JavaScript и Go.
1. Профилирование CPU с помощью cProfile
Промт: «Профилируй этот Python-скрипт с помощью cProfile и найди три самых медленных вызова функций. Выведи время выполнения и количество вызовов для каждой.»
Пример использования:
import cProfile
def slow_function():
total = 0
for i in range(10**6):
total += i ** 2
return total
cProfile.run('slow_function()', 'profile_stats')
Пояснение: cProfile встроен в стандартную библиотеку Python и не требует установки. Вывод показывает, что цикл занимает 99% времени. Это сразу указывает на узкое место — алгоритмическую сложность O(n). Решение: заменить цикл на формулу суммы квадратов (n(n+1)(2n+1)//6), что сократит время с ~0.3 секунды до микросекунд.
2. Поиск утечек памяти с tracemalloc
Промт: «Отследи утечку памяти в этом коде с помощью tracemalloc. Покажи top-3 строки, где выделяется больше всего памяти, и объясни причину.»
Пример использования:
import tracemalloc
tracemalloc.start()
def leak_function():
data = []
for i in range(10000):
data.append({'id': i, 'values': list(range(100))})
return data
leak_function()
snapshot = tracemalloc.take_snapshot()
for stat in snapshot.statistics('lineno')[:3]:
print(stat)
Пояснение: tracemalloc показывает, что строка data.append(...) выделяет 90% памяти. Если функция вызывается в цикле, память не освобождается. Решение: использовать генератор или очищать список после обработки. Инструмент доступен с Python 3.4, документация — docs.python.org/3/library/tracemalloc.html.
3. Бенчмаркинг функций с timeit
Промт: «Сравни производительность двух реализаций: list comprehension и map с lambda. Выполни 10000 повторений и выведи среднее время.»
Пример использования:
python -m timeit -n 10000 '[x**2 for x in range(1000)]'
python -m timeit -n 10000 'list(map(lambda x: x**2, range(1000)))'
Пояснение: timeit автоматически отключает сборщик мусора и выбирает количество повторений. Результат: list comprehension быстрее на ~15% из-за меньших накладных расходов на вызов lambda. Используйте timeit для точных замеров, а не time.time() — он исключает фоновые процессы.
4. Анализ SQL-запросов с EXPLAIN
Промт: «Выполни EXPLAIN ANALYZE для этого запроса в PostgreSQL. Укажи, какие индексы используются, и предложи оптимизацию через добавление индекса или переписывание запроса.»
Пример использования:
EXPLAIN ANALYZE SELECT * FROM orders WHERE status = 'pending' AND created_at > '2026-01-01';
Пояснение: Вывод EXPLAIN показывает Seq Scan (последовательное сканирование) по всей таблице из 1 млн строк — это медленно. Решение: создать композитный индекс CREATE INDEX idx_orders_status_created ON orders(status, created_at). После этого запрос использует Index Scan, время падает с 500 мс до 2 мс. Подробнее — postgresql.org/docs/current/using-explain.html.
5. Профилирование JavaScript с Chrome DevTools
Промт: «Запиши профиль CPU в Chrome DevTools для функции, которая обрабатывает массив из 10000 объектов. Найди функцию с наибольшим временем выполнения и определи, можно ли её оптимизировать с помощью мемоизации.»
Пример использования:
function processItems(items) {
return items.map(item => heavyComputation(item.value));
}
const heavyComputation = (x) => {
for(let i = 0; i < 100000; i++) { x += Math.sqrt(i); }
return x;
};
Пояснение: Вкладка Performance в DevTools показывает, что heavyComputation занимает 80% времени. Если значения повторяются, мемоизация сокращает время в 10 раз. Решение: добавить кеш Map для результатов.
6. Оптимизация циклов с помощью векторизации NumPy
Промт: «Перепиши этот Python-цикл с использованием NumPy для векторизации. Сравни производительность с помощью timeit для массива из 10^6 элементов.»
Пример использования:
import numpy as np
# Медленный цикл
result = [x**2 + 2*x + 1 for x in range(1000000)]
# Векторизованный
arr = np.arange(1000000)
result_np = arr**2 + 2*arr + 1
Пояснение: Векторизация использует C-уровень и SIMD-инструкции. Цикл выполняется ~0.5 секунды, NumPy — ~0.01 секунды. Разница в 50 раз. Это критично для анализа данных или обработки изображений.
7. Анализ боттлнеков в Go с pprof
Промт: «Запусти pprof для этого HTTP-сервера на Go. Найди топ-3 функции по потреблению CPU и предложи оптимизацию через горутины или буферизацию.»
Пример использования:
import "net/http/pprof"
func main() {
go func() { log.Println(http.ListenAndServe(":6060", nil)) }()
// запуск сервера
}
// go tool pprof http://localhost:6060/debug/pprof/profile
Пояснение: pprof показывает, что json.Unmarshal занимает 40% CPU. Решение: использовать json.Decoder с буферизацией или перейти на protobuf. Документация — pkg.go.dev/net/http/pprof.
8. Оптимизация работы с базами данных через N+1 запросы
Промт: «Найди N+1 запросы в этом Django ORM коде. Предложи оптимизацию через select_related или prefetch_related и покажи разницу в количестве запросов.»
Пример использования:
# Проблема: для каждого автора отдельный запрос
authors = Author.objects.all()
for author in authors:
print(author.books.count())
# Оптимизация
authors = Author.objects.prefetch_related('books')
Пояснение: Без prefetch_related выполняется 1+N запросов (1 для авторов, N для книг). С prefetch_related — всего 2 запроса. Для 100 авторов разница очевидна: 101 запрос против 2.
9. Профилирование памяти с memory_profiler
Промт: «Профилируй использование памяти в этой функции построчно с помощью memory_profiler. Найди строку, где выделяется больше всего памяти.»
Пример использования:
from memory_profiler import profile
@profile
def load_data():
large_list = [i for i in range(1000000)]
processed = [x*2 for x in large_list]
return processed
Пояснение: memory_profiler показывает, что large_list занимает 8 MB, а processed — ещё 8 MB. Решение: использовать генератор для экономии памяти. Установка: pip install memory_profiler.
10. Оптимизация асинхронного кода с asyncio
Промт: «Профилируй этот asyncio-код и найди, где происходит блокировка event loop. Предложи замену на неблокирующие вызовы.»
Пример использования:
import asyncio
async def slow_task():
await asyncio.sleep(0.1) # блокирует, если не await
return sum(range(10**6))
Пояснение: Использование time.sleep() вместо asyncio.sleep() блокирует event loop. Профилирование через asyncio.all_tasks() показывает зависшие задачи. Решение: всегда использовать асинхронные версии I/O-операций.
11. Кеширование с Redis для частых запросов
Промт: «Проанализируй этот API-эндпоинт и предложи внедрение кеширования с Redis для данных, которые обновляются раз в час. Покажи пример кода с установкой TTL.»
Пример использования:
import redis
r = redis.Redis()
def get_data():
cached = r.get('key_data')
if cached:
return cached
data = expensive_query()
r.setex('key_data', 3600, data)
return data
Пояснение: Без кеша запрос выполняется 2 секунды, с кешем — <1 мс. TTL 3600 секунд гарантирует актуальность. Это стандартный паттерн для reduce load на БД.
12. Анализ логов с помощью структурного логирования
Промт: «Добавь структурное логирование в этот код и проанализируй время выполнения ключевых операций через парсинг логов. Найди операции, которые занимают больше 100 мс.»
Пример использования:
import structlog
log = structlog.get_logger()
log.info("operation_start", name="query", size=1000)
# ... выполнение
log.info("operation_end", name="query", duration=0.25)
Пояснение: Структурные логи позволяют агрегировать данные по duration. Используйте grep или Elasticsearch для поиска записей с duration > 0.1. Это выявляет медленные запросы без профилирования на проде. Библиотека structlog — structlog.org.
Заключение
Оптимизация производительности — это навык, который требует практики и правильных инструментов. Эти 12 промтов покрывают 80% типовых проблем: от CPU и памяти до БД и асинхронности. Начните с профилирования — без данных оптимизация бесполезна. Используйте cProfile, tracemalloc и EXPLAIN, а затем применяйте кеширование, векторизацию и рефакторинг. Помните: сначала измерьте, потом оптимизируйте. Если хотите углубиться, изучите документацию по каждому инструменту и применяйте их в своих проектах. Удачной оптимизации!
Комментарии