нюансы await в asyncio
Подскажите, пожалуйста, новичку нюансы работы await в asyncio. Пример кода.
import asyncio
async def some_task():
print("Задача начата")
await asyncio.sleep(2)
print("Задача завершена")
async def main():
task = asyncio.create_task(some_task())
#await asyncio.sleep(5)
await task
#await asyncio.sleep(5)
asyncio.run(main())
- Если я просто запускаю await task, тут все понятно, задача выполняется 2 сек
- Если я перед await task ставлю await asyncio.sleep(5), то общее время выполнения программы 5 сек, задачи внутри программы - 2 сек
- Если я после await task ставлю await asyncio.sleep(5), то общее время выполнения программы около 7 сек, задачи внутри программы - 2 сек
Почему в одном случае 2 задачи выполняются "параллельно", а в другом "последовательно"? Заранее спасибо.
Ответы (1 шт):
Давайте посмотрим на описанные вами варианты кода:
task = asyncio.create_task(some_task()) # задача запустилась
await asyncio.sleep(5) # ждём 5с в спячке
await task # без ожидания, т.к. задача уже выполнилась
#await asyncio.sleep(5)
В тот момент, когда вы начинаете ждать 5 секунд задача task
уже работает, вы её запустили через asyncio.create_task
. Поэтому, когда вы начинаете ожидать task
через 5с, она уже выполнилась. Таким образом и получается, что 2с работы task
произошли в тот момент, когда вы делали sleep
и прибавлять эти 2с не нужно, общее время совпадает со временем sleep
. Задачи эти выполнялись параллельно (если для этого хватило потоков, а обычно их хватает).
task = asyncio.create_task(some_task()) # задача запустилась
#await asyncio.sleep(5)
await task # ждём окончания задачи 2с
await asyncio.sleep(5) # ждём ещё 5с в спячке
В этом же случае получается, что вы сначала ждёте задачу task
2с и только потом начинаете ждать sleep
5с, вот и получается 2с ожидания + 5с ожидания = 7с.
Мораль такая: старайтесь по возможности ждать задачи не последовательно, а параллельно. Те задачи, которые могут работать одновременно, собирайте в список и ждите их сразу все вместе, например, через await asyncio.wait
. И делайте это тогда, когда без результата работы этих задач уже нельзя двигаться по коду дальше. А до этого их не нужно ждать, создайте их и пусть работают в фоне. И только те задачи, которые должны выполняться строго последовательно - вот их ждите по очереди, через отдельный await
у каждой такой задачи.