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

Ответ

Основное различие заключается в том, как они обрабатывают блокирующие операции ввода-вывода (I/O) и как это влияет на производительность сервера.

Синхронный обработчик (def)

Это обычная функция Python. Когда она выполняет блокирующую операцию (например, запрос к базе данных, чтение файла, HTTP-запрос с помощью requests), она останавливает выполнение и ждет результата.

Чтобы это не блокировало весь сервер, FastAPI выполняет синхронные функции в отдельном пуле потоков (thread pool). Это позволяет основному циклу событий (event loop) продолжать обрабатывать другие запросы, пока текущий ожидает в своем потоке.

Когда использовать:

  • Для CPU-bound задач (тяжелые вычисления).
  • При использовании библиотек, у которых нет async версии (например, стандартные ORM или requests).

Пример:

import time
from fastapi import FastAPI

app = FastAPI()

@app.get("/sync-route")
def sync_route():
    # Блокирующая операция: поток будет "спать" 2 секунды
    time.sleep(2)
    return {"message": "Done sleeping!"}

Асинхронный обработчик (async def)

Это корутина (coroutine), которая выполняется непосредственно в цикле событий. Когда она встречает await на I/O-операции (например, await async_db.fetch()), она передает управление обратно циклу событий, который может в это время выполнять другие задачи. После завершения I/O-операции выполнение корутины возобновляется.

Это более эффективный способ обработки множества одновременных I/O-запросов, так как не требует создания отдельных потоков для каждого.

Когда использовать:

  • Для I/O-bound задач (работа с сетью, базами данных, файловой системой).
  • При использовании async-совместимых библиотек (httpx, asyncpg, aiofiles).

Пример:

import asyncio
from fastapi import FastAPI

app = FastAPI()

@app.get("/async-route")
async def async_route():
    # Неблокирующая операция: цикл событий не блокируется
    await asyncio.sleep(2)
    return {"message": "Done sleeping asynchronously!"}

Ключевой вывод

  • Используйте async def для операций ввода-вывода с async-библиотеками для максимальной производительности.
  • Используйте def для процессорных задач или при работе с блокирующими библиотеками. FastAPI позаботится о том, чтобы они не блокировали сервер.