Ответ
FastAPI — это современный, высокопроизводительный веб-фреймворк для создания API на Python, который построен на основе Starlette и Pydantic. Он изначально спроектирован для работы с асинхронным кодом, но также эффективно обрабатывает и синхронные функции.
1. Асинхронные операции (async def):
- Принцип работы: FastAPI использует стандартный синтаксис
async/awaitPython для определения асинхронных эндпоинтов. Эти функции выполняются в основном event loop (цикле событий) и предназначены для I/O-bound задач, таких как:- Запросы к базам данных (с асинхронными драйверами, например,
asyncpg,aiomysql). - Внешние HTTP-запросы (с
httpx,aiohttp). - Чтение/запись файлов.
- Любые операции, которые могут 'ждать' ответа от внешнего ресурса.
- Запросы к базам данных (с асинхронными драйверами, например,
- Преимущества: Не блокируют основной поток выполнения, позволяя серверу обрабатывать другие запросы, пока текущий запрос ожидает I/O. Это значительно повышает пропускную способность приложения.
Пример асинхронного эндпоинта:
from fastapi import FastAPI
import httpx # Асинхронный HTTP-клиент
app = FastAPI()
@app.get("/async-data")
async def fetch_external_data():
"""
Асинхронный эндпоинт для получения данных из внешнего API.
Использует httpx для неблокирующего HTTP-запроса.
"""
async with httpx.AsyncClient() as client:
response = await client.get("https://jsonplaceholder.typicode.com/todos/1")
response.raise_for_status() # Выбросить исключение для плохих статусов
return response.json()
2. Синхронные операции (def):
- Принцип работы: Если вы определяете эндпоинт как обычную синхронную функцию (
def), FastAPI автоматически запускает ее в отдельном потоке из внутреннего пула потоков (по умолчаниюThreadPoolExecutor). - Преимущества: Позволяет использовать блокирующие библиотеки или выполнять короткие, быстрые синхронные операции без необходимости переписывать их в асинхронном стиле.
- Ограничения: Длительные синхронные операции (особенно CPU-bound) могут занять поток надолго, уменьшая количество доступных потоков в пуле и потенциально замедляя обработку других синхронных запросов.
Пример синхронного эндпоинта:
import time
from fastapi import FastAPI
app = FastAPI()
@app.get("/sync-message")
def get_sync_message():
"""
Синхронный эндпоинт.
FastAPI запустит его в отдельном потоке.
"""
return {"message": "Это синхронный ответ от FastAPI."}
@app.get("/sync-blocking-task")
def run_blocking_task():
"""
Пример блокирующей CPU-bound задачи.
Не рекомендуется для длительных операций в основном потоке.
"""
time.sleep(2) # Имитация долгой CPU-bound операции
return {"message": "Блокирующая задача выполнена."}
Ключевые рекомендации:
- I/O-bound задачи: Всегда используйте
async defс асинхронными библиотеками (например,asyncpg,httpx,aiofiles). Это максимизирует производительность и отзывчивость вашего API. - CPU-bound задачи: Для длительных вычислений, которые интенсивно используют процессор, избегайте их выполнения напрямую в эндпоинтах. Вместо этого:
- Используйте
asyncio.to_thread()(доступно с Python 3.9) для явного переноса синхронной CPU-bound функции в отдельный поток. - Применяйте
BackgroundTasksдля выполнения некритичных задач после отправки ответа клиенту. - Рассмотрите использование внешних систем очередей задач (например, Celery, Redis Queue) для выполнения тяжелых фоновых процессов.
- Используйте
Понимание различий и правильное применение async def и def функций критически важно для построения высокопроизводительных и масштабируемых приложений на FastAPI.