15 промтов для оптимизации производительности кода: от профилирования до узких мест
Введение
Каждый разработчик сталкивался с ситуацией, когда код работает, но медленно. Особенно это критично в продакшене: пользователи уходят, если страница грузится дольше 3 секунд (данные Google PageSpeed Insights). Оптимизация производительности — это не просто «ускорение», а системный процесс поиска узких мест и их устранения. Я, как практикующий разработчик, ежедневно использую AI-промты для решения таких задач. В этой подборке — 15 проверенных промтов, которые помогут вам быстрее профилировать, находить баги производительности и рефакторить код. Каждый промт сопровождается реальным примером и кодом.
1. Промт для профилирования времени выполнения функции
Промт: «Напиши код для профилирования времени выполнения функции processData в Python с использованием time.perf_counter. Выведи среднее время выполнения за 1000 запусков, минимальное и максимальное значение, а также количество вызовов в секунду. Пример вывода: "Среднее: 0.0023 с, мин: 0.0018 с, макс: 0.0031 с, вызовов/с: 434"».
Пример использования:
import time
def process_data(n):
return sum(i**2 for i in range(n))
# Профилирование
def profile(func, *args, n_runs=1000):
times = []
for _ in range(n_runs):
start = time.perf_counter()
func(*args)
end = time.perf_counter()
times.append(end - start)
avg = sum(times) / len(times)
min_t = min(times)
max_t = max(times)
calls_per_sec = 1 / avg if avg > 0 else float('inf')
print(f"Среднее: {avg:.4f} с, мин: {min_t:.4f} с, макс: {max_t:.4f} с, вызовов/с: {calls_per_sec:.0f}")
profile(process_data, 10000)
Пояснение: Этот промт даёт готовый инструмент для быстрого замера производительности любой функции. Используйте его на этапе тестирования, чтобы сравнить разные реализации.
2. Промт для поиска узких мест с помощью cProfile
Промт: «Напиши скрипт на Python, который использует модуль cProfile для профилирования функции compute_heavy. Выведи топ-10 функций по времени выполнения, отсортированных по cumtime. Пример вывода: "{ncalls: 1000, tottime: 0.5, cumtime: 2.1, filename: script.py:10}"».
Пример использования:
import cProfile
import pstats
def compute_heavy():
total = 0
for i in range(100000):
total += i ** 0.5
return total
cProfile.run('compute_heavy()', 'profile_stats')
p = pstats.Stats('profile_stats')
p.sort_stats('cumtime').print_stats(10)
Пояснение: cProfile — стандартный инструмент Python для профилирования. Промт помогает сразу получить читаемый отчёт, экономя время на настройку.
3. Промт для оптимизации SQL-запросов
Промт: «Дан SQL-запрос: "SELECT * FROM orders WHERE status = 'pending' ORDER BY created_at DESC;". Предложи оптимизации: добавь индексы, измени структуру запроса, объясни, как проверить план выполнения через EXPLAIN. Напиши пример с индексом и без».
Пример использования:
-- Исходный запрос
EXPLAIN ANALYZE SELECT * FROM orders WHERE status = 'pending' ORDER BY created_at DESC;
-- Оптимизированный: составной индекс
CREATE INDEX idx_orders_status_created ON orders(status, created_at DESC);
-- Повторный EXPLAIN
EXPLAIN ANALYZE SELECT * FROM orders WHERE status = 'pending' ORDER BY created_at DESC;
Пояснение: Без индекса база данных сканирует всю таблицу (Seq Scan), что медленно на больших объёмах. Составной индекс ускоряет фильтрацию и сортировку. Используйте EXPLAIN ANALYZE для проверки.
4. Промт для анализа памяти в Python
Промт: «Напиши скрипт для профилирования памяти функции load_large_data с помощью модуля memory_profiler. Выведи потребление памяти в МБ до и после вызова, а также прирост. Пример вывода: "До: 50.2 МБ, После: 120.8 МБ, Прирост: 70.6 МБ"».
Пример использования:
from memory_profiler import memory_usage
def load_large_data():
data = [i for i in range(1000000)]
return sum(data)
mem_before = memory_usage(-1, interval=0.1, timeout=1)[0]
load_large_data()
mem_after = memory_usage(-1, interval=0.1, timeout=1)[0]
print(f"До: {mem_before:.1f} МБ, После: {mem_after:.1f} МБ, Прирост: {mem_after - mem_before:.1f} МБ")
Пояснение: Утечки памяти — частая проблема. Этот промт позволяет быстро оценить, сколько памяти съедает функция.
5. Промт для оптимизации алгоритма сортировки
Промт: «У меня есть список из 10⁶ чисел. Нужно отсортировать его по убыванию. Сравни время выполнения встроенной sorted() и ручной реализации быстрой сортировки. Напиши код с замером времени и выводом разницы. Пример вывода: "sorted(): 0.12 с, quicksort: 2.34 с, разница в 19.5 раз"».
Пример использования:
import random
import time
# Быстрая сортировка (ручная реализация)
def quicksort(arr):
if len(arr) <= 1:
return arr
pivot = arr[len(arr) // 2]
left = [x for x in arr if x > pivot]
middle = [x for x in arr if x == pivot]
right = [x for x in arr if x < pivot]
return quicksort(left) + middle + quicksort(right)
# Тест
data = [random.randint(0, 1000000) for _ in range(100000)]
start = time.time()
sorted_data = sorted(data, reverse=True)
time_sorted = time.time() - start
start = time.time()
qs_data = quicksort(data)
time_qs = time.time() - start
print(f"sorted(): {time_sorted:.4f} с, quicksort: {time_qs:.4f} с, разница в {time_qs/time_sorted:.1f} раз")
Пояснение: Встроенная сортировка в Python (Timsort) оптимизирована на C, поэтому она значительно быстрее ручных реализаций. Промт учит не изобретать велосипед.
6. Промт для кэширования результатов функций
Промт: «Напиши декоратор для кэширования результатов функции с помощью lru_cache из functools. Покажи пример для рекурсивного вычисления чисел Фибоначчи. Сравни время выполнения с кэшем и без. Выведи ускорение в разах».
Пример использования:
from functools import lru_cache
import time
def fib_no_cache(n):
if n < 2:
return n
return fib_no_cache(n-1) + fib_no_cache(n-2)
@lru_cache(maxsize=128)
def fib_cache(n):
if n < 2:
return n
return fib_cache(n-1) + fib_cache(n-2)
n = 35
start = time.time()
fib_no_cache(n)
time_no = time.time() - start
start = time.time()
fib_cache(n)
time_yes = time.time() - start
print(f"Без кэша: {time_no:.4f} с, С кэшем: {time_yes:.4f} с, ускорение в {time_no/time_yes:.0f} раз")
Пояснение: Кэширование — один из самых эффективных способов ускорения рекурсивных алгоритмов. lru_cache автоматически хранит результаты последних вызовов.
7. Промт для параллельного выполнения задач
Промт: «Напиши код на Python, который загружает 10 веб-страниц параллельно с использованием concurrent.futures.ThreadPoolExecutor. Сравни время последовательного и параллельного выполнения. Пример вывода: "Последовательно: 5.2 с, Параллельно: 1.1 с, ускорение в 4.7 раз"».
Пример использования:
import requests
import time
from concurrent.futures import ThreadPoolExecutor
urls = ['https://httpbin.org/delay/1'] * 10
def fetch(url):
return requests.get(url).status_code
# Последовательно
start = time.time()
results_seq = [fetch(url) for url in urls]
time_seq = time.time() - start
# Параллельно
start = time.time()
with ThreadPoolExecutor(max_workers=5) as executor:
results_par = list(executor.map(fetch, urls))
time_par = time.time() - start
print(f"Последовательно: {time_seq:.2f} с, Параллельно: {time_par:.2f} с, ускорение в {time_seq/time_par:.1f} раз")
Пояснение: Для I/O-bound задач (запросы к API, чтение файлов) параллелизм с потоками даёт значительное ускорение.
8. Промт для оптимизации циклов с помощью NumPy
Промт: «Замени цикл на Python для вычисления суммы квадратов элементов массива на векторную операцию NumPy. Сравни время выполнения для массива из 10⁷ элементов. Пример вывода: "Цикл: 3.2 с, NumPy: 0.04 с, ускорение в 80 раз"».
Пример использования:
import numpy as np
import time
n = 10000000
arr = np.random.rand(n)
# Цикл
def sum_sq_loop(arr):
total = 0
for x in arr:
total += x**2
return total
start = time.time()
sum_sq_loop(arr)
time_loop = time.time() - start
# NumPy
start = time.time()
np.sum(arr**2)
time_np = time.time() - start
print(f"Цикл: {time_loop:.4f} с, NumPy: {time_np:.4f} с, ускорение в {time_loop/time_np:.0f} раз")
Пояснение: NumPy использует векторизованные операции на C, что даёт многократное ускорение для численных расчётов.
9. Промт для дебага медленных запросов к API
Промт: «Напиши функцию для замера времени HTTP-запроса с помощью requests и time. Выведи URL, статус код, время ответа и размер ответа в байтах. Пример вывода: "GET https://api.example.com/data -> 200, 0.234 с, 12345 байт"».
Пример использования:
import requests
import time
def time_request(url):
start = time.time()
response = requests.get(url)
elapsed = time.time() - start
size = len(response.content)
print(f"GET {url} -> {response.status_code}, {elapsed:.3f} с, {size} байт")
return elapsed
time_request('https://jsonplaceholder.typicode.com/posts/1')
Пояснение: Этот промт помогает быстро выявить медленные эндпоинты. Добавьте его в тесты или мониторинг.
10. Промт для анализа времени загрузки страницы в браузере
Промт: «Напиши JavaScript-код для измерения времени загрузки страницы с помощью Performance API. Выведи время до DOMContentLoaded, load и общее время. Пример вывода: "DOMContentLoaded: 1.2 с, Load: 2.5 с, Total: 3.0 с"».
Пример использования:
window.addEventListener('load', () => {
const perfData = window.performance.timing;
const domContentLoaded = perfData.domContentLoadedEventEnd - perfData.navigationStart;
const loadTime = perfData.loadEventEnd - perfData.navigationStart;
console.log(`DOMContentLoaded: ${(domContentLoaded / 1000).toFixed(2)} с`);
console.log(`Load: ${(loadTime / 1000).toFixed(2)} с`);
});
Пояснение: Performance API — стандартный инструмент для фронтенд-оптимизации. Промт помогает измерить ключевые метрики.
11. Промт для поиска дублирующихся вычислений
Промт: «Проанализируй следующий код и найди дублирующиеся вычисления. Предложи рефакторинг с кэшированием промежуточных результатов:
def compute(x):
a = x ** 2 + 2 * x + 1
b = x ** 2 + 2 * x + 1
return a + b
Напиши оптимизированную версию с замером времени».
Пример использования:
# Исходный код
def compute_original(x):
a = x ** 2 + 2 * x + 1
b = x ** 2 + 2 * x + 1
return a + b
# Оптимизированный
def compute_optimized(x):
cached = x ** 2 + 2 * x + 1
return cached * 2
# Замер
import time
x = 1000000
start = time.time()
for _ in range(100000):
compute_original(x)
time_orig = time.time() - start
start = time.time()
for _ in range(100000):
compute_optimized(x)
time_opt = time.time() - start
print(f"Исходный: {time_orig:.4f} с, Оптимизированный: {time_opt:.4f} с, ускорение в {time_orig/time_opt:.1f} раз")
Пояснение: Дублирование вычислений — частая ошибка. Промт учит выносить повторяющиеся операции в переменные.
12. Промт для оптимизации работы с файлами
Промт: «Напиши код для чтения большого текстового файла (100 МБ) построчно с помощью генератора. Сравни время чтения всего файла в память и построчного чтения. Выведи разницу в секундах и потребление памяти».
Пример использования:
import time
import sys
# Создаём тестовый файл
with open('test.txt', 'w') as f:
for i in range(10000000):
f.write(f"Line {i}\n")
# Чтение всего файла в память
start = time.time()
with open('test.txt', 'r') as f:
data = f.read()
time_all = time.time() - start
# Построчное чтение
start = time.time()
with open('test.txt', 'r') as f:
for line in f:
pass
time_line = time.time() - start
print(f"Всё в память: {time_all:.4f} с, Построчно: {time_line:.4f} с")
Пояснение: Построчное чтение не загружает весь файл в RAM, что критично при ограниченной памяти.
13. Промт для сравнения времени работы разных структур данных
Промт: «Сравни время выполнения операций поиска, вставки и удаления для списка, множества и словаря в Python для 10⁵ элементов. Напиши код с замерами».
Пример использования:
import time
n = 100000
data_list = list(range(n))
data_set = set(range(n))
data_dict = {i: i for i in range(n)}
# Поиск элемента
start = time.time()
for _ in range(1000):
n-1 in data_list
time_list = time.time() - start
start = time.time()
for _ in range(1000):
n-1 in data_set
time_set = time.time() - start
print(f"Поиск в списке: {time_list:.4f} с, в множестве: {time_set:.4f} с, ускорение в {time_list/time_set:.0f} раз")
Пояснение: Множества и словари используют хеш-таблицы, что даёт O(1) для поиска, в отличие от O(n) для списка.
14. Промт для профилирования времени загрузки страницы в Node.js
Промт: «Напиши middleware для Express.js, который логирует время обработки каждого запроса. Выведи URL, метод, статус, время в миллисекундах. Пример вывода: "GET /api/users 200 45ms"».
Пример использования:
const express = require('express');
const app = express();
app.use((req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
console.log(`${req.method} ${req.url} ${res.statusCode} ${duration}ms`);
});
next();
});
app.get('/', (req, res) => {
setTimeout(() => res.send('Hello'), 100);
});
app.listen(3000);
Пояснение: Middleware-промт для мониторинга производительности API в реальном времени.
15. Промт для оптимизации рендеринга React-компонентов
Промт: «Напиши React-компонент, который использует useMemo и useCallback для предотвращения лишних ререндеров. Покажи пример с профилированием через React.memo и Profiler API».
Пример использования:
import React, { useMemo, useState, Profiler } from 'react';
const ExpensiveComponent = React.memo(({ data }) => {
const processed = useMemo(() => {
return data.map(x => x * 2);
}, [data]);
return <div>{processed.join(',')}</div>;
});
function App() {
const [count, setCount] = useState(0);
const data = useMemo(() => [1, 2, 3], []);
const onRender = (id, phase, actualDuration) => {
console.log(`Компонент {id} отрендерен за {actualDuration} мс`);
};
return (
<Profiler id="App" onRender={onRender}>
<ExpensiveComponent data={data} />
<button onClick={() => setCount(c => c + 1)}>{count}</button>
</Profiler>
);
}
Пояснение: useMemo и React.memo предотвращают повторные вычисления и ререндеры, что критично для сложных UI.
Заключение
Эти 15 промтов покрывают основные сценарии оптимизации: профилирование, кэширование, параллелизм, работа с памятью и структурами данных. Используйте их как шпаргалку при ревью кода или дебаге. Начните с профилирования (промты 1-2) — это покажет, где реальные узкие места. Помните: преждевременная оптимизация — зло, но системный подход с инструментами AI ускорит вашу работу. Попробуйте применить хотя бы один промт сегодня — и вы увидите разницу.
Комментарии