Модуль asyncio Python - Блог ITVDN
ITVDN: курсы программирования
Видеокурсы по
программированию

    Выбери свою IT специальность

    Начать бесплатно

    Выбери свою IT специальность

    Начать бесплатно

      Модуль asyncio Python

      Введение

      Мы продолжаем цикл статей об асинхронном программировании с использованием сопрограмм в Python. В предыдущей статье мы рассмотрели реализацию сопрограмм при помощи генераторов в Python 2.5 и выше, в этой же познакомимся с той инфраструктурой, которая построена на основе них в Python 3.


      В Python 3.4 был включён модуль asyncio, который, на самом деле, был доступен в виде отдельного пакета на PyPI ещё для Python 3.3. Этот модуль предоставляет всю необходимую инфраструктуру для написания однопоточного конкурентного кода с использованием сопрограмм неблокирующего ввода-вывода, мультиплексирования ввода-вывода через сокеты и другие ресурсы, запуска сетевых клиентов и серверов и т.д.

      Его возможности:

      • цикл событий с разными его реализациями, оптимизированными для различных операционных систем;
      • абстракции «транспорта» и «протокола» (подобные тем, что используются в фреймворке Twisted);
      • поддержка TCP, UDP, SSL, конвейеров UNIX-процессов, отложенных вызовов;
      • адаптированный для использования с циклом событий класс Future, который представляет ещё не вычисленный результат асинхронной функции;
      • сопрограммы и задачи, основанные на основе генераторов;
      • поддержка отмены Future и сопрограмм;
      • примитивы синхронизации для использования с сопрограммами;
      • возможность запуска задач в пуле потоков либо пуле процессов, что позволяет даже взаимодействовать с библиотеками, которые совершают блокирующий ввод-вывод.

      В основе модуля asyncio лежит цикл событий (event loop). Он отвечает за:

      • создание задач из сопрограмм и Future и их выполнение;
      • регистрацию, исполнение и отмену отложенных вызовов;
      • создание клиентских и серверных транспортов для различных видов коммуникации;
      • запуск подпроцессов и связи их с транспортами для взаимодействия со внешним процессом;
      • делегирование медленных вызовов обычных функций пулу потоков или пулу процессов.

      Сопрограммы в asyncio – это генераторы, которые отвечают определённым требованиям. Ко всем сопрограммам должен быть применён декоратор @asyncio.coroutine.

      Действия, которые поддерживают сопрограммы asyncio:

      • result = yield from future – приостановка выполнения сопрограммы до получения future значения и присвоение этого значения переменной result (если future отменён, возникает исключение CancelledError);
      • result = yield from coroutine – ожидание завершения работы другой сопрограммы и получение её результата;
      • return result – возврат значения в сопрограмму, ожидающую данную;
      • raise exception – выброс исключения для обработки его ожидающей сопрограммой (если оно не обработано в текущей).

      Рассмотрим пример двух сопрограмм, одна из которых вызывает другую, производящую какие-то затратные вычисления (на самом деле, для простоты примера она будет просто приостанавливать своё выполнение на одну секунду и возвращать квадрат числа).

      import asyncio

      @asyncio.coroutine

      def time_consuming_computation(x):

          print('Computing {0} ** 2...'.format(x))

          yield from asyncio.sleep(1)

          return x ** 2

      @asyncio.coroutine

      def process_data(x):

          result = yield from time_consuming_computation(x)

          print('{0} ** 2 = {1}'.format(x, result))

      if __name__ == '__main__':

          loop = asyncio.get_event_loop()

          loop.run_until_complete(process_data(238))

          loop.close()

      Функция get_event_loop модуля asyncio возвращает объект цикла событий, и мы используем его метод run_until_complete для запуска сопрограммы.

      Какое же в данном случае преимущество перед обыкновенными функциями? Во время работы сопрограммы asyncio.sleep выполнение программы не блокируется, и, если бы у нас были другие запланированные для выполнения задачи, они могли бы в это время выполняться в том же самом потоке.

      Данные сопрограмм

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

      Можем переписать созданный ранее пример при помощи модуля asyncio.

      import asyncio

      import random

      import time

      @asyncio.coroutine

      def consume():

          """Сопрограмма обработки данных"""

          running_sum = 0

          count = 0

          while True:

              data = yield from produce()

              running_sum += data

              count += 1

              print('Got data: {}\nTotal count: {}\nAverage: {}\n'.format(

                  data, count, running_sum / count))

      @asyncio.coroutine

      def produce():

          """Сопрограмма выдачи данных."""

          yield from asyncio.sleep(0.5)

          data = random.randint(0, 100)

          return data

      def main():

          loop = asyncio.get_event_loop()

          loop.run_until_complete(consume())

          loop.close()

      if __name__ == '__main__':

          main()

       

      Обратите внимание, что пришлось изменить логику его работы: теперь основной является сопрограмма consumer, а producer выдаёт одну порцию данных. Причиной этого является рассмотренные ранее ограничения, накладываемые на сопрограммы asyncio, которые логично следуют из основного предназначения данного модуля: совершение асинхронного ввода-вывода. В более реальном примере аналог сопрограммы producer мог бы, например, получать данные с внешнего сервера или базы данных.

      КОММЕНТАРИИ И ОБСУЖДЕНИЯ

      Пакеты подписки с доступом ко всем курсам и сервисам

      Стартовый
      • Все видеокурсы на 3 месяца
      • Тестирование по 10 курсам
      • Проверка 5 домашних заданий
      • Консультация с тренером 30 мин
      Базовый
      • Все видеокурсы на 6 месяцев
      • Тестирование по 16 курсам
      • Проверка 10 домашних заданий
      • Консультация с тренером 60 мин
      Премиум
      • Все видеокурсы на 1 год
      • Тестирование по 24 курсам
      • Проверка 20 домашних заданий
      • Консультация с тренером 120 мин
      Notification success
      Мы используем cookie-файлы, чтобы сделать взаимодействие с нашими веб-сайтами и услугами простым и значимым.