Ответ
Оптимизация производительности POST-запросов в FastAPI включает несколько ключевых подходов, направленных на сокращение времени ответа и уменьшение нагрузки на сервер.
-
Асинхронная обработка Используйте
async defдля эндпоинтов, выполняющих I/O-операции (запросы к БД, внешним API, чтение/запись файлов). Это позволяет серверу обрабатывать другие запросы, не дожидаясь завершения блокирующей операции.@app.post("/items/") async def create_item(item: Item): # Асинхронный вызов к базе данных await db.create_item(item.dict()) return {"status": "ok"} -
Фоновые задачи (Background Tasks) Для длительных операций, результат которых не нужен клиенту немедленно (отправка email, обработка видео), используйте
BackgroundTasks. Сервер вернет ответ клиенту мгновенно, а задача выполнится в фоне.from fastapi import BackgroundTasks def send_confirmation_email(email: str): # ... логика отправки письма time.sleep(5) @app.post("/register/") async def register_user(user: User, tasks: BackgroundTasks): # ... логика сохранения пользователя tasks.add_task(send_confirmation_email, user.email) return {"message": "User registered, confirmation email is being sent."} -
Пакетная обработка (Batching) Вместо отправки множества запросов на создание одиночных сущностей, реализуйте эндпоинт, принимающий список объектов. Это сокращает сетевой оверхед и позволяет выполнять пакетные операции с БД (например,
bulk_insert).from typing import List @app.post("/items/batch/") async def create_multiple_items(items: List[Item]): # Логика пакетной вставки в БД await db.bulk_create_items([item.dict() for item in items]) return {"status": "created", "count": len(items)} -
Оптимизация работы с БД
- Используйте индексы для полей, по которым происходит поиск или проверка уникальности.
- Выбирайте только необходимые поля (
SELECT col1, col2...) вместоSELECT *. - Используйте асинхронные драйверы для баз данных (например,
asyncpgдля PostgreSQL).
-
Профилирование Используйте профилировщики, такие как
cProfileилиpy-spy, чтобы найти "узкие места" в коде, которые потребляют больше всего времени.
Ответ 18+ 🔞
А, слушай, вот эта тема про то, как POST-запросы в FastAPI не ебать мозг серверу — это же святое, блядь! Ну то есть, если ты не хочешь, чтобы твой сервис лег, как мудак пьяный, при первом же нашествии пользователей, то надо немного подумать головой. Не просто так, а с пристрастием, ёпта!
Вот смотри, основные моменты, где можно всё просрать, если не аккуратно.
1. Асинхронность — твой новый бог, блядь.
Ну серьёзно, если твой эндпоинт тупо ждёт, пока база данных почешется, или файл запишется, или ещё какая-то хуйня случится, то он в это время просто занимает место, как мудак в очереди за пивом. А другие запросы стоят и ждут. Пиздец картина.
Вот поэтому надо юзать async def. Это как дать ему понять: «Слушай, дружок, пошёл ты ждать, я пока другим людям помогу, а как база ответит — я вернусь к тебе».
@app.post("/items/")
async def create_item(item: Item):
# Не тупим, ждём асинхронно, пока база не протрезвеет
await db.create_item(item.dict())
return {"status": "ok"}
Вот так, а не иначе. Иначе — волнение ебать, все встанут колом.
2. Фоновые задачи — чтобы клиент не скучал, пока ты ебёшься с тяжёлой работой.
Представь: пользователь зарегистрировался, а ты ему такой — «Ща, братан, я тебе письмо отправлю, это на пять минут». Он будет сидеть и пялиться в экран? Да хуй там! Он уйдёт и больше не вернётся, пидарас шерстяной!
Поэтому всё, что можно отложить — откладывай в BackgroundTasks. Ответил пользователю мгновенно — «Всё окей!» — а сам в фоне уже делаешь, что надо.
from fastapi import BackgroundTasks
def send_confirmation_email(email: str):
# ... тут какая-то долгая ебля с SMTP
time.sleep(5) # условно
@app.post("/register/")
async def register_user(user: User, tasks: BackgroundTasks):
# ... сохранили юзера быстро
tasks.add_task(send_confirmation_email, user.email) # А письмо пусть само шлётся, когда сможет
return {"message": "User registered, confirmation email is being sent."}
Клиент доволен, сервер не нагружен, все в шоколаде. Красота, блядь!
3. Пакетная обработка — не будь мудаком, не делай тысячу запросов по одному.
Это же просто пиздец, когда кто-то шлёт тебе сто запросов подряд на создание товаров. Сетевой оверхед — овердохуища, нагрузка на базу — просто жесть. В рот меня чих-пых!
Сделай один эндпоинт, который принимает список, и вставь всё разом. Базы это любят, они для такого bulk_insert придуманы.
from typing import List
@app.post("/items/batch/")
async def create_multiple_items(items: List[Item]):
# Один раз ебнул — и сто записей в таблице. Эффективно, сука!
await db.bulk_create_items([item.dict() for item in items])
return {"status": "created", "count": len(items)}
Вот это по-взрослому. Не как мартышлюшка, которая по одной банану таскает.
4. База данных — тут вообще отдельная песня, блядь. Ты можешь написать самый асинхронный и красивый код, но если в базе нет индекса на поле, по которому ты ищешь уникальность пользователя, то всё — пизда. Запрос будет выполняться сто лет, сервер будет тупить, а ты будешь чесать репу.
- Индексы — это как указатели в книге. Без них искать — это пиздец какой-то.
- *Не выбирай всё подряд (`SELECT
)**. Зачем тебе все поля, если нужны толькоidиname`? Ты что, коллекционер? Бери только то, что нужно. - Асинхронные драйверы (
asyncpg,aiomysqlи т.д.) — это must have. Иначе вся твоя асинхронность нахуй не сдалась, потому что драйвер базы будет всё блокировать.
5. Профилирование — когда уже ничего не помогает, а пиздец наступает.
Бывает такое: вроде всё сделал по уму, а сервер всё равно тормозит, как хуй в проруби. Подозрение ебать чувствую — где-то тут собака зарыта.
Вот тут надо брать в руки тяжёлую артиллерию: cProfile, py-spy. Эти штуки покажут тебе, какая конкретно функция или строчка кода жрёт 95% времени. Может, ты там в цикле десять тысяч раз к базе ходишь? Или JSON какой-то здоровенный бездумно парсишь? Узнаешь — исправишь.
Без этого ты как слепой кот — будешь тыкаться носом, а результата ноль, блядь.
Короче, суть в чём: не надо делать всё в лоб, на авось. Думай, что и когда делать. FastAPI — инструмент мощный, но если им размахивать, как дубиной, то можно и по пальцам получить. Удачи, не проёбывайся!