ASGI объяснил: будущее веб-разработки на Python

автор vadim


Веб-приложения Python уже давно соответствуют стандарту интерфейса шлюза веб-сервера (WSGI), который описывает, как они взаимодействуют с веб-серверами. WSGI, первоначально представленный в 2003 году и обновленный в 2010 году, опирается только на функции, которые изначально были доступны в Python версии 2.2 и которые было легко реализовать. В результате WSGI быстро прижился во всех основных веб-фреймворках Python и стал краеугольным камнем веб-разработки на Python.

Перенесемся в 2022 год. Python 2 устарел (наконец-то), и у Python теперь есть собственный синтаксис для обработки асинхронных операций, таких как сетевые вызовы. WSGI и другие стандарты, которые по умолчанию предполагают синхронное поведение, не могут воспользоваться преимуществами производительности и эффективности асинхронности. Это, в свою очередь, означает, что WSGI не может эффективно обрабатывать расширенные протоколы, такие как WebSocket.

Введите ASGI, интерфейс шлюза асинхронного сервера. Как и WSGI, ASGI описывает общий интерфейс между веб-приложением Python и веб-сервером. В отличие от WSGI, ASGI допускает несколько асинхронных событий для каждого приложения. Кроме того, ASGI поддерживает как синхронизирующие, так и асинхронные приложения. Вы можете перенести свои старые синхронные веб-приложения WSGI в ASGI, а также использовать ASGI для создания новых асинхронных веб-приложений.

Как работает WSGI

WSGI работает, предоставляя функцию Python, обычно называемую application или app, на веб-сервер. Эта функция принимает два параметра:

  • environ: словарь, содержащий информацию о текущем запросе и переменных среды, предоставленных веб-сервером.
  • start_response: функция, которая будет использоваться для инициации отправки HTTP-ответа обратно клиенту.

Данные, возвращаемые функцией, составляют тело ответа.

Просто application функция может выглядеть так:

def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/plain')])
    return [b'Greetings universe']

Если вы используете WSGI-совместимую веб-платформу, например Flask, сама платформа предоставит application функция, все ее компоненты подключаются автоматически.

Недостатки WSGI двояки. Во-первых, WSGI одновременно обрабатывает только один запрос и ответ, предполагая, что ответ будет возвращен немедленно. Невозможно справиться с длительными соединениями, такими как WebSocket или HTTP-соединение с длительным опросом.

Во-вторых, WSGI работает только синхронно. Даже если вы используете многопоточный пул соединений, каждое соединение будет блокироваться до тех пор, пока не вернет ответ. Многие настройки WSGI имеют возможность обрабатывать пулы потоков и процессов, но они ограничены интерфейсом WSGI. сам быть синхронным.

Как работает ASGI

ASGI внешне похож на WSGI. Как и в случае с WSGI, вы определяете application функциональный объект, за исключением того, что это async функция с тремя параметрами вместо двух:

  • scope: словарь с информацией о текущем запросе, аналогичный environ в WSGI, но с немного другим соглашением об именах для деталей.
  • send: Ан async вызываемая (функция), которая позволяет приложению отправлять сообщения обратно клиенту.
  • receive: Ан async вызываемый, который позволяет приложению получать сообщения от клиента.

Простой ASGI application функция может выглядеть так:

 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!',
    })

Как и веб-фреймворк WSGI, веб-фреймворк ASGI генерирует свои собственные application() функционировать и подключить его по мере необходимости.

Наиболее очевидное отличие ASGI заключается в том, что мы используем асинхронные метафоры во всей функции. Сама функция asyncи мы отправляем HTTP-заголовки и тело ответа посредством двух отдельных await send() команды. Таким образом, сама функция и ее send команды, ничего не блокировать; они могут чередоваться с вызовами application и send от многих других соединений одновременно.

Мы не используем receive в этом примере, но это тоже async функция. Это позволяет нам получать тело запроса, не блокируя другие операции. Таким образом, запросы и ответы могут передаваться на сервер или с него постепенно — то, чего мы не могли бы сделать элегантно, а может быть, и вообще, с помощью WSGI.

Использование функций синхронизации и асинхронности с ASGI

При использовании ASGI вам нужно будет использовать async функций и асинхронных библиотек, насколько это возможно. Стоит выработать привычку использовать async, поскольку проблемы с использованием кода только для синхронизации могут быть существенными. Любой длительный вызов функции, предназначенной только для синхронизации, заблокирует всю цепочку вызовов, в результате чего преимущества использования асинхронности практически исчезнут.

Если вы застряли в длительном синхронном вызове чего-либо, используйте asyncio.run_in_executor передать вызов потоку или пулу процессов. Пул потоков следует использовать всякий раз, когда вы ожидаете внешнего события или задачи, не нагружающей процессор. Пул процессов следует использовать для локальных задач, интенсивно использующих ЦП.

Например, если в вашем веб-приложении есть маршрут, который осуществляет вызов удаленного веб-сайта, вам следует использовать поток — или, еще лучше, использовать метод aiohttp библиотека, которая выполняет асинхронные HTTP-запросы. Если вы хотите вызвать библиотеку изображений Pillow для изменения размера изображения, вам, вероятно, следует использовать run_in_executor с пулом процессов. Несмотря на то, что при пересылке данных между процессами туда и обратно потребуются небольшие накладные расходы, использование run_in_executor не будет блокировать другие события.

Готовые к ASGI веб-фреймворки

Веб-приложения ASGI можно писать «вручную», реализуя application() объект. Но в подавляющем большинстве случаев будет проще (и меньше головной боли) использовать асинхронную, ориентированную на ASGI веб-инфраструктуру Python. Вот несколько распространенных вариантов веб-фреймворка, которые хорошо сочетаются с ASGI:

  • Старлетт и FastAPI: Эти многообещающие фреймворки (FastAPI построен на основе Starlette) в первую очередь асинхронны, поэтому неудивительно, что они оба поддерживают ASGI. Если вы начинаете веб-приложение с чистого листа, это самые современные и передовые веб-фреймворки для Python.
  • Кварта: Хотя основной веб-фреймворк Python Flask поддерживает ASGI, Flask не предназначен изнутри для использования преимуществ асинхронных метафор. Quart из GitLab использует синтаксис и метафоры Flask, но допускает асинхронные обработчики маршрутов.
  • Джанго 3.0 и более поздние версии: Начиная с Django 3.0, почтенная веб-инфраструктура Django поддерживает ASGI. Поддержка асинхронного кода в приложении Django вместо возможности простого монтирования Django на обработчике ASGI была добавлена ​​в Django 3.1. Для платформы, не известной своей скоростью выполнения, простое наличие асинхронности обеспечивает более высокую производительность для тех, кто решит ее использовать.

Related Posts

Оставить комментарий