Я пытаюсь правильно понять и реализовать два одновременно работающих Task объектов, используя Python 3 относительно новый asyncio.
В двух словах asyncio, похоже, предназначен для обработки асинхронных процессов и параллельного выполнения Task по циклу событий. Это способствует использованию await (применяется в асинхронных функциях) как обратный вызов для ожидания и использования результата без блокировки цикла события. (Фьючерсы и обратные вызовы по-прежнему являются жизнеспособной альтернативой.)
Он также предоставляет класс asyncio.Task(), специализированный подкласс Future, предназначенный для переноса сопрограмм. Предпочтительно вызывается с помощью метода asyncio.ensure_future(). Предполагаемое использование задач asyncio - позволить независимо запущенным задачам запускаться "одновременно" с другими задачами в пределах одного цикла событий. Я понимаю, что Tasks связаны с циклом события, который затем автоматически продолжает управлять сопрограммой между операторами await.
Мне нравится идея использовать одновременные Задачи без необходимости использовать один из классов Executor, но у меня нет нашел много проработки в отношении реализации.
Вот как я это делаю сейчас:
import asyncio
print('running async test')
async def say_boo():
i = 0
while True:
await asyncio.sleep(0)
print('...boo {0}'.format(i))
i += 1
async def say_baa():
i = 0
while True:
await asyncio.sleep(0)
print('...baa {0}'.format(i))
i += 1
# OPTION 1: wrap in Task object
# -> automatically attaches to event loop and executes
boo = asyncio.ensure_future(say_boo())
baa = asyncio.ensure_future(say_baa())
loop = asyncio.get_event_loop()
loop.run_forever()
В случае попытки одновременного запуска двух задач цикла, я заметил, что, если у задачи нет внутреннего выражения await, он застрянет в цикле while, эффективно блокируя выполнение других задач (много как обычный цикл while). Однако, как только Задачи должны (а) ждать, они, кажется, запускаются одновременно без проблем.
Таким образом, операторы await, как представляется, обеспечивают цикл событий с плацдармом для переключения между задачами, давая эффект concurrency.
Пример вывода с внутренним await:
running async test
...boo 0
...baa 0
...boo 1
...baa 1
...boo 2
...baa 2
Пример вывода без внутреннего await:
...boo 0
...boo 1
...boo 2
...boo 3
...boo 4
Вопросы
Проходит ли эта реализация для "правильного" примера параллельных циклов Задачи в asyncio?
Правильно ли, что единственный способ, которым это работает, - это Task предоставить точку блокировки (выражение await), чтобы цикл события мог манипулировать несколькими задачами?