← Назад к вопросам

В чем разница между асинхронным и синхронным ендпойтом в FastAPI?

2.0 Middle🔥 231 комментариев
#FastAPI и Flask#Асинхронность и многопоточность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разница между асинхронным и синхронным эндпойтом в FastAPI

Это критически важный вопрос для понимания производительности FastAPI. FastAPI поддерживает оба подхода, и выбор между ними зависит от характера операций в эндпойте.

Синхронный эндпойт

Синхронный эндпойт — это обычная функция Python, которая выполняется последовательно, блокируя поток выполнения на время работы.

from fastapi import FastAPI
import time

app = FastAPI()

@app.get("/users/{user_id}")
def get_user(user_id: int):
    # Блокирует поток на 2 секунды
    time.sleep(2)
    return {"id": user_id, "name": "John"}

Когда клиент делает запрос:

  1. FastAPI выделяет один из потоков из пула рабочих потоков
  2. Функция выполняется полностью до конца
  3. Поток занят и не может обрабатывать другие запросы
  4. Когда функция завершается, поток освобождается

Асинхронный эндпойт

Асинхронный эндпойт — это async функция, которая может "приостанавливаться" и "возобновляться", освобождая поток во время ожидания.

from fastapi import FastAPI
import asyncio

app = FastAPI()

@app.get("/users/{user_id}")
async def get_user(user_id: int):
    # Освобождает поток на 2 секунды
    await asyncio.sleep(2)
    return {"id": user_id, "name": "John"}

Когда клиент делает запрос:

  1. FastAPI запускает async функцию
  2. Когда встречается await, функция приостанавливается
  3. Поток освобождается и может обрабатывать другие запросы
  4. Когда операция завершается, функция возобновляется

Основные различия

ПараметрСинхронныйАсинхронный
Синтаксисdef function()async def function()
Ожиданиеtime.sleep()await asyncio.sleep()
БлокированиеБлокирует потокОсвобождает поток
Одновременные запросыN запросов = N потоковМножество запросов = 1 поток
Потребление памятиБольше (один поток на запрос)Меньше (один поток на многие)
Производительность I/OНизкая (если много операций БД)Высокая (идеально для I/O)
CPU-bound операцииХороший выборПлохой выбор

Практический пример: обработка 1000 запросов

Синхронный вариант

from fastapi import FastAPI
import time

app = FastAPI()

@app.get("/sync-endpoint")
def sync_endpoint():
    # Каждый запрос занимает 1 секунду
    time.sleep(1)
    return {"message": "Done"}

# 1000 запросов × 1 сек = 1000 секунд
# Если у вас 4 рабочих потока: 1000 / 4 = 250 секунд

Асинхронный вариант

from fastapi import FastAPI
import asyncio

app = FastAPI()

@app.get("/async-endpoint")
async def async_endpoint():
    # Каждый запрос ждёт 1 секунду, но освобождает поток
    await asyncio.sleep(1)
    return {"message": "Done"}

# 1000 запросов × 0 сек (с точки зрения потока) = ~1 секунда
# Все 1000 запросов могут выполняться одновременно!

Когда использовать синхронный?

Синхронный эндпойт используй, если операция:

  • CPU-bound (вычисление, обработка данных)
  • Использует синхронные библиотеки (например, обычный requests)
  • Очень быстрая (< 10 мс)
import requests  # Синхронная библиотека

@app.get("/calculate")
def calculate():
    # CPU-bound операция
    result = sum(range(1000000))
    return {"result": result}

@app.get("/sync-api")
def call_external_api():
    # Синхронный запрос (может быть медленным!)
    response = requests.get("https://api.example.com/data")
    return response.json()

Когда использовать асинхронный?

Асинхронный эндпойт используй, если операция:

  • I/O-bound (запросы в БД, HTTP запросы)
  • Использует асинхронные библиотеки (aiohttp, sqlalchemy async)
  • Может быть медленной (> 100 мс)
import httpx
from sqlalchemy.ext.asyncio import AsyncSession

@app.get("/async-api")
async def call_external_api():
    # Асинхронный HTTP запрос
    async with httpx.AsyncClient() as client:
        response = await client.get("https://api.example.com/data")
    return response.json()

@app.get("/async-db")
async def get_user_async(session: AsyncSession, user_id: int):
    # Асинхронный запрос в БД
    user = await session.execute(
        select(User).where(User.id == user_id)
    )
    return user.scalar()

Реальный пример: параллельные запросы

from fastapi import FastAPI
import httpx
import asyncio

app = FastAPI()

# ПЛОХО - синхронно, очень медленно
@app.get("/sync-multiple")
def sync_multiple():
    urls = [f"https://api.example.com/data/{i}" for i in range(10)]
    results = []
    
    for url in urls:
        # Каждый запрос ждёт 1 сек = 10 секунд всего
        response = requests.get(url)
        results.append(response.json())
    
    return {"results": results}

# ХОРОШО - асинхронно, параллельно
@app.get("/async-multiple")
async def async_multiple():
    urls = [f"https://api.example.com/data/{i}" for i in range(10)]
    
    async with httpx.AsyncClient() as client:
        # Все 10 запросов выполняются параллельно = ~1 сек всего
        tasks = [client.get(url) for url in urls]
        responses = await asyncio.gather(*tasks)
        results = [r.json() for r in responses]
    
    return {"results": results}

Важный нюанс: чистые функции

Если в эндпойте используется синхронная (не асинхронная) функция с I/O операциями, FastAPI автоматически запускает её в отдельном потоке:

@app.get("/blocking-but-safe")
def blocking_operation():
    # Это запустится в отдельном потоке, не блокируя главный event loop
    import requests
    response = requests.get("https://api.example.com/data")
    return response.json()

# FastAPI использует ThreadPoolExecutor для синхронных операций
# Это медленнее, чем асинхронный вариант, но безопаснее

Чек-лист: выбор между async и sync

┌─ Это I/O операция?
│  ├─ Да → Используй async + await
│  └─ Нет → Идёшь дальше
│
└─ Это CPU-bound операция?
   ├─ Да → Используй sync def
   └─ Нет → Используй async def (на всякий случай)

Итоговый вывод

  • Синхронный эндпойт блокирует поток и хорош для быстрых CPU-операций
  • Асинхронный эндпойт освобождает поток и хорош для I/O-операций
  • Для I/O-bound операций (БД, HTTP) обязательно используй async — это даст огромный прирост производительности
  • FastAPI может смешивать оба подхода в одном приложении
  • Асинхронная версия может быть на 100x быстрее для I/O-bound операций!