Асинхронные возможности Python

Асинхронность:

Модель

<!> Предполагается, что весь предлагаемый код вы запускаете и смотрите на результат; без этого понять намного сложнее, if even possible ☺

Асинхронность как произвольное исполнение частей кода между yield-ами

Можно и дальше усложнять, но и так уже непросто!

Ещё модели

Синтаксис Async

Перепишем предыдущий пример на async

Asyncio

Базоавя документация

Основные понятия:

И толстый-толстый слой шоколада!

Д/З

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

  2. EJudge: FilterQueue 'Очередь с фильтром'

    Напишите класс FilterQueue со следующими свойствами:

    • Это потомок asyncio.Queue

    • В экземпляре класса атрибут очередь.window содержит первый элемент очереди, или None, если очередь пуста

    • С помощью операции фильтр in очередь можно определить, присутствуют ли в очереди такие элементы, что выражение фильтр(элемент) истинно

    • Метод .later() синхронно переставляет первый элемент очереди в её конец, или вызывает исключение asyncio.QueueEmpty, если очередь пуста

    • Метод .get() содержит необязательный параметр фильтр. Вызов очередь.get(фильтр) работает так:

      • Если в очереди нет элементов, на которых фильтр(элемент) истинно, работает как обычный .get().

      • Если в очереди есть элементы, на которых фильтр(элемент) истинно, переставляет первый элемент очереди в её конец до тех пор, пока фильтр(элемент) не истинно, а затем выполняет обычный .get().

    • Разрешается воспользоваться внутренним представлением Queue

    Input:

       1 async def putter(n, queue):
       2     for i in range(n):
       3         await queue.put(i)
       4 
       5 async def getter(n, queue, filter):
       6     for i in range(n):
       7         await asyncio.sleep(0.1)
       8         yield await queue.get(filter)
       9 
      10 async def main():
      11     queue = FilterQueue(10)
      12     asyncio.create_task(putter(20, queue))
      13     async for res in getter(20, queue, lambda n: n % 2):
      14         print(res)
      15 
      16 asyncio.run(main())
    
    Output:

    1
    3
    5
    7
    9
    11
    13
    15
    17
    4
    19
    12
    6
    16
    8
    14
    0
    10
    2
    18
  3. EJudge: NotifyEvent 'Оповещения'

    Написать класс NotifyEvent (унаследованный от asyncio.Event) со следующими свойствами

    • В методе оповещение.set(имя) присутствует строка-имя адресата уведомления, но по умолчанию это None

    • Перед каждым оповещение.set() (кроме самого первого) требуется вызов оповещение.clear()

    • Метод await оповещение.wait() возвращает имя адресата уведомления (но в остальном работает как event.wait())

    Написать также сопрограмму task(имя, оповещение) со следующими свойствами:

    • Если уведомление «своё» — адресат уведомления совпадает с именем, — выводится имя, количество принятых «своих» уведомлений и количество принятых «чужих» уведомлений

    • Если вместо имени await оповещение.wait() вернул None, работа завершается

    • Использовать внутреннюю реализацию asyncio.Event в этой задаче нельзя

    Input:

       1 async def sender(names, notify):
       2     for name in names:
       3         notify.set(name)
       4         await asyncio.sleep(0.1)
       5         notify.clear()
       6     notify.set()
       7 
       8 async def main():
       9     notify = NotifyEvent()
      10     tasks = {n: task(n, notify) for n in "12"}
      11     targets = "1", "2", "2", "2", "2", "1", "2", "1", "1"
      12     await asyncio.gather(*(list(tasks.values()) + [sender(targets, notify)]))
      13 
      14 asyncio.run(main())
    
    Output:

    1: 1 / 0
    2: 1 / 1
    2: 2 / 1
    2: 3 / 1
    2: 4 / 1
    1: 2 / 4
    2: 5 / 2
    1: 3 / 5
    1: 4 / 5

TODO Тесты

LecturesCMC/PythonIntro2022/13_Async (последним исправлял пользователь FrBrGeorge 2022-12-09 17:38:29)