Питон 3.5; Асинхронный/Ожидание

Тихо и незаметно (с), Выпущена версия Python 3.5 ! И, конечно же, одно из самых интересных нововведений релиза — новый синтаксис определения сопрограмм с помощью ключевых слов.

асинхронный/ожидание , далее в статье об этом.

Вид поверхности «PEP 0492 — Сопрограммы с синтаксисом async и await» Сначала у меня возник вопрос: «Зачем это нужноЭ» Сопрограммы удовлетворительно реализованы на расширенных генераторах и на первый взгляд может показаться, что все сводится к замене выход из на Ждите и декоратор, создающий сопрограмму на асинхронный .

Сюда же можно добавить ощущение, что все это делалось исключительно для использования с модулем.

асинхронный .

Но это, конечно, не так, тема глубже и интереснее.



сопрограмма
Главное, наверное, то, что теперь сопрограмма в Python — это специальный объект собственная сопрограмма , а не какой-то специально разработанный генератор или что-то еще.

Этот объект имеет стандартные библиотечные методы и функции для работы с ним.

То есть теперь это объект, определенный как часть языка.



Ждите
К сожалению, в документации и PEP я не нашел краткого определения того, для чего было введено это новое ключевое слово.

Рискну сформулировать это сам: Ключевое слово Ждите указывает, что при выполнении следующего выражения можно переключиться с текущей сопрограммы на другую или на основной поток выполнения.

Соответственно, выражение после Ждите это тоже не просто, это должно быть ожидаемый объект.

ожидаемый объект
Существует три варианта ожидаемых объектов:
  • Другая сопрограмма, а именно объект собственная сопрограмма .

    Этот похож и, видимо, реализован аналогично случаю, когда в генераторе с использованием выход из вызывается другой генератор.

  • Сопрограмма на основе генератора, созданная с помощью декоратора типы.

    coroutine() .

    Это вариант обеспечения совместимости с разработками, где сопрограммы реализованы на основе генераторов.

  • Специальный объект, в котором реализован магический метод. __Ждите__ , возвращая итератор.

    Используя этот итератор, возвращается результат выполнения сопрограммы.

Пример того, как написать самому ожидаемый Я не нашел объекта ни в PEP, ни в документации, по крайней мере на момент написания этой статьи.

Ниже этот недостаток будет исправлен.

)

асинхронный
В ПЭП содержится десяток параграфов с заголовками «Почему…» и «Почему бы и нет…».

Практически все они посвящены вопросу, почему это ключевое слово используется именно так, а не иначе.

И действительно, асинхронная защита выглядит в коде странно и заставляет задуматься, а не «питонический ли это путь»? С другой стороны, понятно, что им хотелось какой-то более целостной картины, поскольку есть и асинхронный для И асинхронно с .

  • асинхронная защита — определяет встроенная функция сопрограммы , результатом которого будет объект сопрограммы собственная сопрограмма , еще не запущен.

  • асинхронный для — определяет, что используемый в цикле итератор при получении следующего значения может переключить выполнение с текущей сопрограммы.

    Объект-итератор вместо стандартных магических методов имеет: __iter__ И __следующий__ , методы: __aiter__ И __anext__ .

    Функционально они схожи, но, как следует из определения, допускают использование await в своем теле.

  • асинхронно с — определяет, что при входе и выходе из контекстного блока выполнение может переключаться с текущей сопрограммы.

    То же, что и в случае с асинхронным генератором, вместо магических методов: __входить__ И __Выход__ следует использовать функционально аналогичные __aenter__ И __aexit__ .

В определениях, данных в PEP, говорится, что «асинхронный код» можно вызывать в магических методах.

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

Примеров использования асинхронных итераторов и контекстных менеджеров в документации и PEP достаточно, юзекейс в целом понятен и всё логично.

Единственное, что непонятно, — зачем использовать версии магических методов с разными именами, ведь они все равно объявляются с использованием `async def`.

Видимо это что-то связанное с особенностями реализации; Другого объяснения я не вижу.



Как его приготовить?

Изучение какой-то новой функции языка или библиотеки быстро приводит к вопросу о том, как и где ее использовать.

А более глубокое исследование, на мой взгляд, следует продолжить на практическом примере.

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

Формулировка задачи следующая: «Вызов функции сна должен остановить выполнение сопрограммы на определенное время».

Сопрограммы и управление событиями хорошо сочетаются друг с другом.

другая моя статья подробнее, почему я так думаю.

И пример такого рода хорошо продемонстрирует нам практически все возможности и нюансы использования сопрограмм.

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

Тогда практическая реализация может быть такой:

  • Функция сна настраивает диспетчер событий на вызов функции обратного вызова через указанный период времени.

    После этого он передает управление основному потоку выполнения (то есть диспетчеру).

  • Функция обратного вызова, переданная диспетчеру, вызывается по истечении указанного времени.

    Он переключается на сопрограмму и передает ей полезную информацию.

Это можно было бы закодировать примерно так:
   

from time import time from collections import deque from tornado.ioloop import IOLoop current = deque() class sleep(object): def __init__(self, timeout): self.deadline = time() + timeout def __await__(self): def swith_to(coro): current.append(coro) coro.send(time()) IOLoop.instance().

add_timeout(self.deadline, swith_to, current[0]) current.pop() return (yield) def coroutine_start(run, *args, **kwargs): coro = run(*args, **kwargs) current.append(coro) coro.send(None) if __name__ == '__main__': async def hello(name, timeout): while True: now = await sleep(timeout) print("Hello, {}!\tts: {}".

format(name, now)) coroutine_start(hello, "Friends", 1.0) coroutine_start(hello, "World", 2.5) IOLoop.instance().

start()

Как видите, код короткий, вполне понятный и, кстати, рабочий.

Опишу в ней основные моменты:

  1. Используется в качестве диспетчера событий торнадо.

    ioloop.IOLoop На мой взгляд комментировать тут особо нечего.

  2. Сорт спать - реализует ожидаемый объект, его функция — передать управление диспетчеру событий, предварительно настроив его на вызов перезвонить после определенного периода времени.

  3. Функция обратного вызова определяется как замыкание, но в данном случае это не имеет значения.

    Его цель — просто переключить выполнение обратно на сопрограмму, передав текущее время.

    Переключение выполнения на сопрограмму осуществляется вызовом ее метода отправлять или метод бросать для переключения с выдачей исключений.

  4. Функция Назначение coroutine_start — это создать сопрограмму путем вызова фабричной функции и запустить ее на исполнение.

    Первый вызов метода отправлять сопрограммы, должны иметь параметр Никто - это запускает сопрограмму

  5. Сама функция привет тривиально.

    Это может быть и понятно, но я думаю, стоит уточнить.

    Эта функция не является сопрограммой! Функция, создающая и возвращающая сопрограмму (фабричная функция), аналогична функциям, создающим и возвращающим генератор.

Развитие этой идеи: «async/await coroutine и event-driven», вы можете увидеть перейдите по этой ссылке .

Он еще сырой, но помимо продемонстрированного переключения по событию «таймаут» реализовано переключение сопрограмм по событиям «Ввод-вывод готов» и «системный сигнал».

В качестве демонстрации приведен пример асинхронного эхо-сервера.



Окончательно

Сопрограммы были доступны в том или ином виде уже довольно давно, но «официальных правил игры с ними» не существовало.

Теперь эти «правила игры» определены и закреплены, и это станет хорошим поводом для более широкого использования методов асинхронного программирования в Python. В опросе могут участвовать только зарегистрированные пользователи.

Войти , Пожалуйста.

async/await как реализация асинхронного программирования на Python 74,51% Асинхронное программирование на Python необходимо, рассматриваемая реализация приемлема.

576 17,08% Асинхронное программирование на Python необходимо, но рассматриваемая реализация неприемлема.

132 8,41% Асинхронное программирование на Python не требуется 65 Проголосовали 773 пользователя.

462 пользователя воздержались.

Теги: #python 3.5 #async #await #awaitable #asyncio #tornado #coroutine #управляемый событиями #цикл событий #диспетчер событий #python #программирование #проектирование и рефакторинг #Алгоритмы #Параллельное программирование

Вместе с данным постом часто просматривают: