Асинхронный django. Фильм 4-й: Воскрешение

от автора

Поздравляю вас с Новым годом кролика и желаю сбычи всех мечт! Это статья о том, что версия django на гринлетах скоро получит новую, более изящную форму. Какую — смотрите ниже. fibers — это новое название, потому что предыдущее — greenhack — никуда не годилось.

async def myview(request):     async with fibers:         # Здесь можно использовать django         obj = MyObject.objects.get()         print(obj.related_obj)      # Здесь можно писать асинхронный код     await notify_somebody(request)

Теперь, использовать django внутри асинхронной функции можно под (асинхронным) контекстным менеджером — fibers. По-моему, юзабилити сильно выигрывает. И семантически — тоже понятнее, что происходит, нет?

Вы спросите — почему было сразу так не сделать. Дело в том, что мне только недавно пришло в голову, что это технически возможно. Конечно — при условии, если вспомнить, как реализованы корутины в питоне (это генераторы), и воспользоваться этой особенностью реализации. Для нетерпеливых — вот ссылка на gist.

Как же можно воспользоваться тем, что корутины — это генераторы? Приведу простой пример:

async def hi():     print('hi')

Несмотря на то, что перед нами асинхронная функция, необязательно иметь event loop, чтобы запустить её. Можно, вместо этого, сделать так:

try:   gen = hi()   gen.send(None) except StopIteration:     pass

У контекстного менеджера fibers — такой же принцип. Он устроен так, что весь код внутри него можно выполнить вызовом gen.send() (вот эта строчка). Дальше, мы оборачиваем этот вызов в гринлет и применяем наш обычный подход.

Я обещал написать простейший Awaitable. Но, поскольку многие читатели и сами могут это сделать (хоть для практических нужд это не нужно), мой вариант будет немного необычным:

class Simple:     def __await__(self):         return 'hi'         yield

await Simple()вернёт'hi'. Слово yield делает функцию генератором, но, конечно, до него не доходит выполнение.__await__— это генератор. В отличие от корутин, он может делать как yield, так и yield from. Тогда как корутины могут делать только await, что соответствует yield from.

Контекстный менеджер fibers использует кастомные Awaitable, которые делают yield специальных значений 'start' и 'end'. Event loop их не поймёт. Поэтому нам нужно обернуть какую-нибудь корутину (верхнего уровня, например), чтобы она не пропускала их наружу. Сделать это относительно несложно: например, если у нас — ASGI приложение, то можно обернуть это приложение целиком.

Иллюстрацию подхода можно посмотреть в gist. Код, действительно, достаточно черновой, но дело в том, что это просто ещё один «фронтенд» к библиотеке greenhack — для него даже не потребовалось вносить туда изменения. «Вещь в себе», короче говоря.

Когда всё будет готово? Всё упирается в асинхронный бэкенд для джанго. Он готов, но не протестирован: нужно пройти testsuite для бэкендов django. Там около 70 тестов — когда они будут проходить, проект будет готов к продакшну. Обещать по срокам ничего не буду, но буду писать недельные отчёты (нет, не на хабре, на гитхабе). К сожалению, рабочие проекты не связаны с этой темой.

Тем временем, в django вмерджили бэкенд для драйвера psycopg3. Таким образом, если раньше я пользовался форком django для своего бэкенда, то теперь в этом необходимости нет. Вообще, конечно, аплодисменты тем, кто делает такие масштабные пул-реквесты, когда это люди со стороны. У меня, я чувствую, и строчки не получилось бы протащить в репозиторий django. К счастью, в случае с fibers это и не нужно.

Кстати, названием проект обязан языку Ruby, точнее, Ruby Fibers. Дело в том, что в Ruby нет async/await, для асинхронности там в принципе не используются «функции другого цвета». Это обеспечивает ту самую совместимость блокирующего кода с асинхронным, от которой в питоне отказались. К лучшему или нет — я не берусь сказать. Но я знаю, как это «исправить» — для тех случаев, когда эта совместимость нужна.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Как Вам эти пляски с генераторами?
0% Да, ловкий подход 0
0% Не согласен: явное лучше неявного 0
0% Всё очень плохо 0
Никто еще не голосовал. Воздержались 2 пользователя.

ссылка на оригинал статьи https://habr.com/ru/post/708946/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *