Асинхронен ли asgi
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
# Асинхронен ли ASGI?
Ответ: Не совсем. ASGI (Asynchronous Server Gateway Interface) поддерживает асинхронность, но сама по себе не является асинхронной. Это спецификация, которая может работать как синхронно, так и асинхронно.
Что такое ASGI?
ASGI - это стандарт взаимодействия между веб-сервером и Python приложением для работы с HTTP, WebSocket и других асинхронных протоколов. Это как WSGI (для синхронных приложений), но расширенный для поддержки асинхронности.
WSGI и ASGI: Основные отличия
WSGI (Synchronous)
ВSGI - это синхронный интерфейс. Каждый запрос обрабатывается отдельным процессом или потоком. Пока обрабатывается один запрос, он полностью блокирует ресурс.
def application(environ, start_response):
status = "200 OK"
response = b"Hello World"
start_response(status, [("Content-Type", "text/plain")])
return [response]
ASGI (Может быть асинхронным или синхронным)
ASGI - это спецификация, которая позволяет ASGI приложению быть как асинхронным, так и синхронным:
# Асинхронное ASGI приложение
async def application(scope, receive, send):
await send({
"type": "http.response.start",
"status": 200,
"headers": [[b"content-type", b"text/plain"]],
})
await send({
"type": "http.response.body",
"body": b"Hello World",
})
# Синхронное ASGI приложение - тоже допустимо!
def application(scope, receive, send):
send({
"type": "http.response.start",
"status": 200,
})
send({
"type": "http.response.body",
"body": b"Hello World",
})
ASGI поддерживает ОБА типа кода
Это критически важное понимание: ASGI сервер (вроде Uvicorn, Hypercorn) может работать как с асинхронным, так и с синхронным кодом приложения.
Пример с FastAPI - асинхронный
from fastapi import FastAPI
import aiohttp
app = FastAPI()
@app.get("/users/{user_id}")
async def get_user(user_id: int):
async with aiohttp.ClientSession() as session:
async with session.get(f"https://api.example.com/users/{user_id}") as resp:
data = await resp.json()
return data
Пример с FastAPI - синхронный
from fastapi import FastAPI
import requests
app = FastAPI()
@app.get("/users/{user_id}")
def get_user(user_id: int):
response = requests.get(f"https://api.example.com/users/{user_id}")
return response.json()
Второй код тоже будет работать в ASGI приложении, но менее эффективно.
Как ASGI сервер обрабатывает синхронный код?
Когда вы используете синхронную функцию в ASGI приложении, Uvicorn запускает её в отдельном потоке, чтобы не блокировать event loop:
import asyncio
from concurrent.futures import ThreadPoolExecutor
# Внутри Uvicorn
async def handle_sync_endpoint(endpoint_func):
loop = asyncio.get_event_loop()
result = await loop.run_in_executor(
ThreadPoolExecutor(),
endpoint_func
)
return result
Так что синхронный код выполняется в отдельном потоке, не блокируя главный event loop.
ASGI - это про ИНТЕРФЕЙС, не про асинхронность
ASGI - это способ обмена информацией между сервером и приложением через три параметра:
async def app(scope, receive, send):
# scope - информация о запросе (метод, путь, заголовки)
# receive - функция для получения событий от сервера
# send - функция для отправки событий к серверу
if scope["type"] == "http":
body = b""
while True:
message = await receive()
if message["type"] == "http.request":
body += message.get("body", b"")
if not message.get("more_body", False):
break
await send({
"type": "http.response.start",
"status": 200,
})
await send({
"type": "http.response.body",
"body": b"Response: " + body,
})
Сравнение WSGI и ASGI
| Параметр | WSGI | ASGI |
|---|---|---|
| Назначение | HTTP только | HTTP, WebSocket, другие |
| Синхронность | Только синхронный | Оба типа кода |
| Производительность | Процессы/потоки | Event loop |
| Примеры серверов | Gunicorn | Uvicorn, Hypercorn |
| Примеры фреймворков | Flask, Django | FastAPI, Starlette |
Реальный пример: FastAPI
from fastapi import FastAPI
app = FastAPI()
@app.get("/async")
async def async_endpoint():
import asyncio
await asyncio.sleep(1)
return {"type": "async"}
@app.get("/sync")
def sync_endpoint():
import time
time.sleep(1)
return {"type": "sync"}
Оба работают. Но асинхронный лучше - он не блокирует event loop.
Проблемы синхронного кода в ASGI
Хотя синхронный код работает, он имеет недостатки:
# Плохо - блокирует event loop
@app.get("/slow")
def slow_endpoint():
import time
time.sleep(10) # Блокирует!
return {"status": "done"}
# Хорошо - не блокирует event loop
@app.get("/fast")
async def fast_endpoint():
import asyncio
await asyncio.sleep(10) # Не блокирует
return {"status": "done"}
Вывод
ASGI сам по себе НЕ асинхронен. Это просто спецификация интерфейса. Но ASGI поддерживает асинхронность и может работать с обоими типами кода. Для максимальной производительности ASGI приложение должно использовать асинхронный код с async/await.