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

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

    Подписка
    РУС
    • РУС
    • УКР
    Arrow
    27 марта состоится вебинар «Подготовка к собеседованию по PHP» Подробности и регистрация
    Arrow

    Модуль asyncio Python

    advertisement advertisement

    Введение

    Мы продолжаем цикл статей об асинхронном программировании с использованием сопрограмм в 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 мог бы, например, получать данные с внешнего сервера или базы данных.

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

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

    Библиотека современных IT знаний в удобном формате

    Выбирай свой вариант подписки в зависимости от задач, стоящих перед тобой. Но если нужно пройти полное обучение с нуля до уровня специалиста, то лучше выбирать Базовый или Премиум. А для того чтобы изучить 2-3 новые технологии, или повторить знания, готовясь к собеседованию, подойдет Пакет Стартовый.

    Стартовый
    • Все видеокурсы на 3 месяца
    • Тестирование по 10 курсам
    • Проверка 5 домашних заданий
    • Консультация с тренером 30 мин
    59.99 $
    Оформить подписку
    Весенний
    • Все видеокурсы на 15 месяцев
    • Тестирование по 24 курсам
    • Проверка 20 домашних заданий
    • Консультация с тренером 120 мин
    90.00 $
    219.99 $
    Оформить подписку
    Акция
    Премиум
    • Все видеокурсы на 1 год
    • Тестирование по 24 курсам
    • Проверка 20 домашних заданий
    • Консультация с тренером 120 мин
    169.99 $
    Оформить подписку
    Notification success