сеньорчикОткрыть в Telegram
← вся теориятеория к собесу · FastAPI, Django и API

WSGI и ASGI

WSGI и ASGI: два контракта сервер↔приложение

Между веб-сервером и Python-приложением стоит контракт, и то, какой он - синхронный WSGI или асинхронный ASGI - определяет, что твой сервис вообще способен делать. Собес проверяет это, чтобы понять, разберёшься ли ты, почему WebSocket не заводится или почему FastAPI нельзя запустить обычным gunicorn.

Типовые формулировки: «в чём разница WSGI и ASGI?», «почему Flask не держит WebSocket?», «чем запускать FastAPI в прод».

WSGI синхронный, ASGI асинхронный

WSGI (web server gateway interface) (PEP 3333) - синхронный контракт: callable с environ и start_response, один запрос - один вызов. На нём стоит весь классический sync-стек: Flask, Django-sync. Модель «запрос-ответ» проста, но не оставляет места для долгого двустороннего канала - WebSocket нативно не держит.

ASGI (asynchronous server gateway interface) - асинхронный преемник: async/await, а значит WebSocket, SSE (server-sent events), долгие соединения. На нём FastAPI, Starlette, Django-async; сервер - uvicorn или hypercorn. Именно поэтому WebSocket требует ASGI: под WSGI его просто некуда встроить.

// Запустить FastAPI обычным sync-gunicorn нельзя - ASGI-приложению нужен uvicorn-воркер (или gunicorn с uvicorn.workers).

WSGI
синхронный стандарт сервер↔приложение (PEP 3333)
ASGI
асинхронный преемник WSGI: async, websockets, стриминг
PEP
Python Enhancement Proposal

Как каждый набирает конкурентность

Sync-фреймворк под gunicorn набирает конкурентность числом воркеров и потоков: gunicorn -w N поднимает N процессов, память растёт с их числом. Хочешь держать больше одновременных запросов - добавляешь воркеров, и упираешься в память.

Один uvicorn-воркер держит тысячи соединений корутинами в одном потоке на event loop - по памяти несравнимо дешевле. Но у этого есть цена: CPU-счёт или блокирующий вызов в корутине заморозит ВЕСЬ воркер со всеми его соединениями, тогда как у sync-воркера пострадал бы только один процесс.

// Автопул FastAPI (обычный def в threadpool) применяется только к sync-эндпоинтам; блокировка прямо в async def душит loop.

gunicorn
WSGI/менеджер воркеров; конкурентность процессами
uvicorn
ASGI-сервер на event loop для async-приложений

Как отвечать: «В чём разница WSGI и ASGI, что когда брать?»

WSGI - синхронный контракт из PEP 3333: один запрос, один вызов, модель строго запрос-ответ. На нём Flask и классический Django, конкурентность набирается процессами через gunicorn. ASGI - асинхронный преемник: он умеет async/await, а значит WebSocket, SSE и долгие соединения, которые в WSGI просто некуда встроить. На нём FastAPI и Django-async, сервер uvicorn. Беру ASGI, когда нужны реальный async-I/O, вебсокеты или стриминг; для простого sync-CRUD хватает WSGI. Главное - не перепутать сервер: FastAPI под sync-gunicorn не поднимется, ему нужен uvicorn.

Названы обе природы (sync/async), конкретные фреймворки и серверы, критерий выбора и практический подводный камень с запуском - законченная картина стека.

На чём валят

  • Ждать WebSocket от Flask на sync-gunicorn: модель WSGI долгие соединения не тянет - нужен ASGI.
  • Запускать FastAPI обычным sync-gunicorn: ASGI-приложению нужен uvicorn-воркер.
  • «async-фреймворк делает любой код неблокирующим»: блокировка в async def всё равно душит цикл.
  • Забыть, что один упавший в блокировку uvicorn-воркер тянет за собой все свои соединения, а не один запрос.

Проверьте себя

Пять вопросов из банка по этой подтеме. Всего их 13, остальные разбираются в тренажёре.

  1. #wsgi_asgi1 / 5
    Что такое WSGI?
    A)Веб-сервер, написанный специально под фреймворк Django
    B)Синхронный контракт «сервер ↔ Python-приложение»
    C)Асинхронный протокол для веб-сокетов и стриминга данных
    D)Формат конфигурации маршрутов внутри веб-приложения
    показать ответ и разбор
    +B)Синхронный контракт «сервер ↔ Python-приложение»

    // разбор: WSGI (PEP 3333) — стандарт синхронного интерфейса между веб-сервером (gunicorn/uWSGI) и Python-приложением (Flask, Django-sync): callable принимает environ и start_response. Один запрос — один синхронный вызов. На нём стоит весь классический sync-стек Python-веба.

  2. #wsgi_asgi2 / 5
    Что добавляет ASGI поверх WSGI?
    A)Асинхронность, websockets и долгие соединения
    B)Только более быстрый парсинг входящих HTTP-заголовков
    C)Обязательную типизацию всех эндпоинтов приложения
    D)Встроенную ORM для работы приложения с базой данных
    показать ответ и разбор
    +A)Асинхронность, websockets и долгие соединения

    // разбор: ASGI — асинхронный преемник WSGI: поддерживает async/await, WebSocket, Server-Sent Events и долгоживущие соединения, которых синхронная модель WSGI (запрос-ответ) не тянет. На ASGI стоят FastAPI, Starlette, Django-async; сервер — uvicorn/hypercorn.

  3. #wsgi_asgi3 / 5
    Почему классический WSGI-стек (Flask на gunicorn-sync) не держит WebSocket нативно?
    A)Библиотека WSGI просто пока не реализовала поддержку websocket
    B)Модель WSGI — короткий запрос-ответ, без долгих каналов
    C)WebSocket требует другого языка исполнения, не Python
    D)gunicorn физически не способен открывать сетевые сокеты
    показать ответ и разбор
    +B)Модель WSGI — короткий запрос-ответ, без долгих каналов

    // разбор: WSGI спроектирован как синхронный цикл «пришёл запрос → вернул ответ», без места для длительного двустороннего канала. WebSocket — долгоживущее соединение, ему нужен ASGI (и uvicorn). Отсюда переезд на ASGI, когда в проекте появляются сокеты, SSE или стриминг.

  4. #wsgi_asgi4 / 5
    Sync-фреймворк под gunicorn: как он обслуживает многих клиентов сразу?
    A)Несколькими воркерами и потоками, а не через async
    B)Отдаёт всю конкурентность целиком на сторону nginx
    C)Он вообще не умеет конкурентность — строго по одному клиенту
    D)Одним процессом, мультиплексируя корутины внутри цикла
    показать ответ и разбор
    +A)Несколькими воркерами и потоками, а не через async

    // разбор: Синхронный WSGI-воркер обрабатывает один запрос за раз, поэтому конкурентность набирают числом воркеров (процессов) и потоков: gunicorn -w N, плюс gthread/gevent. Это не async-модель — параллелизм даёт ОС и число воркеров, а память растёт с их количеством.

  5. #wsgi_asgi5 / 5
    Один uvicorn-воркер с async-FastAPI держит тысячи одновременных соединений. За счёт чего?
    A)ASGI сам распараллеливает соединения по ядрам процессора
    B)Uvicorn поднимает отдельный поток на каждое соединение
    C)Один поток мультиплексирует корутины на event loop
    D)Каждое соединение уходит в свой отдельный процесс-воркер
    показать ответ и разбор
    +C)Один поток мультиплексирует корутины на event loop

    // разбор: ASGI-воркер на event loop держит тысячи корутин в одном потоке: пока одни ждут I/O, цикл обслуживает других. Отсюда высокий конкаренси на малом числе воркеров. Но CPU-счёт или блокирующий вызов в корутине заморозит весь воркер — как и в чистом asyncio.

дальше

Теорию прочитали. Навык ставится повторением

В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, лимит только на количество вопросов в день.