Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save Eugene-Fed/1041360f2c2492b4c8635cb9ec31b470 to your computer and use it in GitHub Desktop.

Select an option

Save Eugene-Fed/1041360f2c2492b4c8635cb9ec31b470 to your computer and use it in GitHub Desktop.

В FastAPI-приложениях часто используются синхронные библиотеки, которые могут блокировать event loop, если не вынесены в отдельные потоки. Вот список самых распространённых:


📚 1. Работа с базами данных

Библиотека Назначение Асинхронный аналог
psycopg2 PostgreSQL asyncpg, sqlalchemy.ext.asyncio
mysql-connector-python MySQL aiomysql
sqlite3 SQLite aiosqlite
SQLAlchemy (синхронный режим) ORM SQLAlchemy 2.0+ (async)
pymongo MongoDB motor

Пример проблемы:

# Синхронный запрос к PostgreSQL (блокирует loop, даже в `def`-маршруте!)
from sqlalchemy import create_engine
engine = create_engine("postgresql://user:pass@localhost/db")

@app.get("/sync-db")
def sync_db():
    with engine.connect() as conn:
        result = conn.execute("SELECT * FROM users")  # Блокирующий вызов
    return {"data": result.fetchall()}

🌐 2. HTTP-запросы

Библиотека Асинхронный аналог
requests httpx.AsyncClient, aiohttp
urllib3 Встроен в httpx

Пример:

import requests

@app.get("/sync-http")
def sync_http():
    r = requests.get("https://api.example.com")  # Блокирует поток
    return r.json()

📂 3. Работа с файлами

Библиотека Асинхронный аналог
Встроенный open() aiofiles
pandas.read_csv()/to_csv() polars (частично async)
json.load()/dump() aiofiles + json

Пример:

@app.get("/read-file")
def read_file():
    with open("large_file.csv") as f:  # Блокирующая операция
        data = f.read()
    return {"size": len(data)}

🔢 4. Математика и Data Science

Библиотека Проблема Решение
numpy CPU-bound ProcessPoolExecutor
pandas CPU-bound + GIL То же
scikit-learn CPU-bound Вынос в отдельные процессы

Пример:

import pandas as pd

@app.get("/process-data")
def process_data():
    df = pd.read_csv("data.csv")  # Загружает в потоке
    result = df.mean().to_dict()  # CPU-операция
    return result

5. Утилиты и системные вызовы

Библиотека/Модуль Асинхронная альтернатива
time.sleep() asyncio.sleep()
subprocess.run() asyncio.create_subprocess_exec
os.walk() aiofiles.os.walk() (через сторонние решения)

Пример:

import time

@app.get("/delay")
def delay():
    time.sleep(5)  # Блокирует поток
    return {"message": "Готово"}

🛠 6. Другие популярные синхронные библиотеки

  • Авторизация: passlib, bcrypt → Асинхронных аналогов нет (выносить в потоки).
  • Кэширование: redis-pyaioredis.
  • Шаблонизация: Jinja2jinja2.Environment (но обычно быстрая, не критично).

📌 Критические последствия

  1. В async def-маршрутах синхронные библиотеки полностью блокируют event loop.
  2. В def-маршрутах они работают в потоках, но:
    • При высокой нагрузке пул потоков исчерпывается.
    • CPU-операции страдают от GIL.

Рекомендации по исправлению

  1. Для def-маршрутов:

    • Увеличить пул потоков (если I/O-bound):
      import concurrent.futures
      pool = concurrent.futures.ThreadPoolExecutor(max_workers=100)
    • Для CPU-bound: ProcessPoolExecutor.
  2. Для async def-маршрутов:

    • Всегда использовать asyncio.to_thread():
      await asyncio.to_thread(requests.get, "https://api.example.com")
    • Или переходить на async-аналоги (httpx, asyncpg).
  3. Глобальное решение:
    Постепенная замена синхронных библиотек на асинхронные.


📊 Сводная таблица решений

Тип операции Синхронная библиотека Стратегия оптимизации
I/O-bound (БД, HTTP) psycopg2, requests Пул потоков или async-аналоги
CPU-bound (математика) numpy, pandas ProcessPoolExecutor
Файлы open(), pandas.read_csv() aiofiles, потоки
Утилиты time.sleep() asyncio.sleep()

Главное правило: Всегда проверяйте документацию библиотеки на предмет async-поддержки. Если её нет — планируйте вынос в потоки или процессы.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment