Ответ
Чтобы не блокировать пользователя во время выполнения длительных операций на сервере (например, генерации отчета или сложного рендеринга), применяют несколько подходов, которые выносят работу из основного потока обработки запроса.
Основной принцип — как можно быстрее вернуть пользователю первоначальный ответ, а тяжелую задачу выполнить в фоне.
1. Фоновые задачи (Background Tasks)
Идеально для тяжелых, ресурсоемких операций, которые могут выполняться несколько секунд или минут. Клиент получает ответ немедленно, а результат задачи можно получить позже через другой эндпоинт или WebSocket.
- Инструменты: Celery, RQ (Redis Queue).
# tasks.py
from celery import Celery
app = Celery('tasks', broker='redis://localhost:6379/0')
@app.task
def generate_report_async(user_id: int):
# ... логика генерации тяжелого отчета ...
print(f"Report for user {user_id} is ready!")
return True
# main.py (например, FastAPI)
@app.post("/reports/")
def create_report(user_id: int):
generate_report_async.delay(user_id)
return {"message": "Report generation started. You will be notified upon completion."}
2. Асинхронные фреймворки
Подходят для I/O-bound операций (запросы к базам данных, внешним API), где основной поток ждет ответа от внешнего ресурса. async/await позволяет эффективно переключать контекст, не блокируя весь процесс.
- Инструменты: FastAPI, aiohttp, Quart.
# FastAPI
import asyncio
from fastapi import FastAPI
app = FastAPI()
async def fetch_data_from_external_api():
# Имитация долгого сетевого запроса
await asyncio.sleep(5)
return {"data": "some important data"}
@app.get("/data")
async def get_data():
# Этот вызов не блокирует сервер, он может обрабатывать другие запросы
external_data = await fetch_data_from_external_api()
return {"content": external_data}
3. Потоковая передача данных (Streaming)
Используется, когда контент можно генерировать и отдавать по частям. Клиент начинает получать данные сразу, не дожидаясь полной готовности.
- Инструменты: WebSockets, Server-Sent Events (SSE), StreamingResponse в FastAPI/Starlette.
# FastAPI StreamingResponse
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
import asyncio
app = FastAPI()
async def slow_data_generator():
for i in range(10):
yield f"Data chunk {i}n"
await asyncio.sleep(1)
@app.get("/stream")
async def stream_data():
return StreamingResponse(slow_data_generator()) Ответ 18+ 🔞
А, слушай, вот это тема, блядь! Чтобы пользователь не сидел как лох, уставившись в пустой экран, пока сервер там что-то ебёт мозги, есть куча способов, ёпта.
Основная идея — побыстрее плюнуть пользователю хоть какой-то ответ, типа «принято, работаем», а всю тягомотину свалить в фон. Чтобы он не думал, что всё накрылось медным тазом.
1. Фоновые задачи (Background Tasks)
Это когда у тебя есть какая-то пиздопроебищная операция — типа сгенерировать отчёт на триста страниц или видео обработать. Отправляешь её в очередь, а сам сразу говоришь юзеру: «Всё ок, иди попей чайку».
- Инструменты: Celery, RQ (это типа очередь через Redis).
# tasks.py
from celery import Celery
app = Celery('tasks', broker='redis://localhost:6379/0')
@app.task
def generate_report_async(user_id: int):
# ... логика генерации тяжелого отчета ...
print(f"Report for user {user_id} is ready!")
return True
# main.py (например, FastAPI)
@app.post("/reports/")
def create_report(user_id: int):
generate_report_async.delay(user_id)
return {"message": "Report generation started. You will be notified upon completion."}
Вот видишь? Тыкнул кнопку — сразу получил сообщение. А сервер уже сам, втихаря, эту хуйню в фоне дожуёт. Красота, блядь!
2. Асинхронные фреймворки
Это для случаев, когда твоё приложение не столько считает, сколько ждёт. Ждёт ответа от базы данных, от другого сервиса, от какого-нибудь ёбанного API, который отвечает, как черепаха в сиропе. Вместо того чтобы тупо висеть и пялиться в потолок, async/await позволяет переключаться на другие задачи.
- Инструменты: FastAPI, aiohttp.
# FastAPI
import asyncio
from fastapi import FastAPI
app = FastAPI()
async def fetch_data_from_external_api():
# Имитация долгого сетевого запроса
await asyncio.sleep(5)
return {"data": "some important data"}
@app.get("/data")
async def get_data():
# Этот вызов не блокирует сервер, он может обрабатывать другие запросы
external_data = await fetch_data_from_external_api()
return {"content": external_data}
Пока эта функция «спит», ожидая ответа от внешнего API, сервер может обслуживать других юзеров. Не то чтобы магия, но очень эффективно, ёпта.
3. Потоковая передача данных (Streaming)
А это вообще цирк! Когда результат можно нарезать как колбасу и выдавать по кусочку. Пользователь начинает получать данные сразу, с первой же нарезки, а не ждёт, пока весь чурбан перетрут.
- Инструменты: WebSockets, Server-Sent Events (SSE), StreamingResponse в FastAPI.
# FastAPI StreamingResponse
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
import asyncio
app = FastAPI()
async def slow_data_generator():
for i in range(10):
yield f"Data chunk {i}n"
await asyncio.sleep(1)
@app.get("/stream")
async def stream_data():
return StreamingResponse(slow_data_generator())
Представь: ты запрашиваешь лог файла на гигабайт. Вместо того чтобы десять минут грузить одну здоровенную хуйню, тебе его начинают сливать построчно, прямо сейчас. Удобно, блядь, волшебство просто!