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, остальные разбираются в тренажёре.
- Что такое WSGI?A)Веб-сервер, написанный специально под фреймворк DjangoB)Синхронный контракт «сервер ↔ Python-приложение»C)Асинхронный протокол для веб-сокетов и стриминга данныхD)Формат конфигурации маршрутов внутри веб-приложения
показать ответ и разбор
+B)Синхронный контракт «сервер ↔ Python-приложение»// разбор: WSGI (PEP 3333) — стандарт синхронного интерфейса между веб-сервером (gunicorn/uWSGI) и Python-приложением (Flask, Django-sync): callable принимает environ и start_response. Один запрос — один синхронный вызов. На нём стоит весь классический sync-стек Python-веба.
- Что добавляет 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.
- Почему классический WSGI-стек (Flask на gunicorn-sync) не держит WebSocket нативно?A)Библиотека WSGI просто пока не реализовала поддержку websocketB)Модель WSGI — короткий запрос-ответ, без долгих каналовC)WebSocket требует другого языка исполнения, не PythonD)gunicorn физически не способен открывать сетевые сокеты
показать ответ и разбор
+B)Модель WSGI — короткий запрос-ответ, без долгих каналов// разбор: WSGI спроектирован как синхронный цикл «пришёл запрос → вернул ответ», без места для длительного двустороннего канала. WebSocket — долгоживущее соединение, ему нужен ASGI (и uvicorn). Отсюда переезд на ASGI, когда в проекте появляются сокеты, SSE или стриминг.
- Sync-фреймворк под gunicorn: как он обслуживает многих клиентов сразу?A)Несколькими воркерами и потоками, а не через asyncB)Отдаёт всю конкурентность целиком на сторону nginxC)Он вообще не умеет конкурентность — строго по одному клиентуD)Одним процессом, мультиплексируя корутины внутри цикла
показать ответ и разбор
+A)Несколькими воркерами и потоками, а не через async// разбор: Синхронный WSGI-воркер обрабатывает один запрос за раз, поэтому конкурентность набирают числом воркеров (процессов) и потоков: gunicorn -w N, плюс gthread/gevent. Это не async-модель — параллелизм даёт ОС и число воркеров, а память растёт с их количеством.
- Один uvicorn-воркер с async-FastAPI держит тысячи одновременных соединений. За счёт чего?A)ASGI сам распараллеливает соединения по ядрам процессораB)Uvicorn поднимает отдельный поток на каждое соединениеC)Один поток мультиплексирует корутины на event loopD)Каждое соединение уходит в свой отдельный процесс-воркер
показать ответ и разбор
+C)Один поток мультиплексирует корутины на event loop// разбор: ASGI-воркер на event loop держит тысячи корутин в одном потоке: пока одни ждут I/O, цикл обслуживает других. Отсюда высокий конкаренси на малом числе воркеров. Но CPU-счёт или блокирующий вызов в корутине заморозит весь воркер — как и в чистом asyncio.
дальше
Теорию прочитали. Навык ставится повторением
В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, лимит только на количество вопросов в день.