Python Asyncio запутался в ожидании и задачах - PullRequest
0 голосов
/ 23 мая 2019

Завершите здесь новость, прочитав о Задачи Asycnio , в которых есть этот пример:

import asyncio
import time

async def say_after(delay, what):
    await asyncio.sleep(delay)
    print(what)

async def main():
    task1 = asyncio.create_task(
        say_after(1, 'hello'))

    task2 = asyncio.create_task(
        say_after(2, 'world'))

    print(f"started at {time.strftime('%X')}")

    # Wait until both tasks are completed (should take
    # around 2 seconds.)
    await task1
    await task2

    print(f"finished at {time.strftime('%X')}")

asyncio.run(main())

Мое первоначальное понимание await состоит в том, что он блокирует выполнение текущей функции и ожидает возврата асинхронной функции.

Но в этом случае обе сопрограммы выполняются одновременно, это не очень хорошо подходит для моего понимания await. Может кто-нибудь объяснить, пожалуйста?

Дальнейшее расследование, добавив дополнительные print в say_after, мне кажется, что сопрограмма не начинается, пока не произойдет await ...

import asyncio
import time

async def say_after(delay, what):
    print('Received {}'.format(what))
    await asyncio.sleep(delay)
    print(what)

async def main():
    task1 = asyncio.create_task(
        say_after(1, 'hello'))

    task2 = asyncio.create_task(
        say_after(2, 'world'))

    print(f"started at {time.strftime('%X')}")

    # Wait until both tasks are completed (should take
    # around 2 seconds.)
    await task1
    await task2

    print(f"finished at {time.strftime('%X')}")

asyncio.run(main())

печать

started at 13:41:23
Received hello
Received world
hello
world
finished at 13:41:25

Ответы [ 3 ]

1 голос
/ 23 мая 2019

Когда вы инкапсулируете сопрограмму в объекте Task (или Future), сопрограмма готова к работе, поэтому, когда цикл событий запускается с первого ожидания, запускаются и task1, и task2.

Чтобы сделать его более понятным, для выполнения сопрограммы вам понадобятся две вещи:
1) сопрограмма, инкапсулированная в будущем объекте (Task), чтобы сделать ее ожидаемой
2) работающий цикл обработки событий

В вашем примере выполнение работает следующим образом:
1 - create_task1
2 - create_task2
3 - ожидание задачи1
4 - ожидание сна задачи1
5 - ожидание сна задачи2

теперь и задача 1, и задача 2 спят, поэтому предположим, что задача 1 завершается первой (некоторое время спит)

6 - печать задачи 1
7 - ожидание задачи 2
8 - печатьof task2

теперь конец цикла

Как вы сказали, когда вы получили ожидание, выполнение останавливается, но позвольте мне сказать, что оно останавливается только в текущем «потоке выполнения», когда высоздать будущее (Задача), вы создаете другое exucution fнизкий, и в ожидании просто переключиться на текущий поток выполнения.Это последнее объяснение не совсем правильно в смысле терминов, но помогает прояснить его.

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

1 голос
/ 23 мая 2019

Ваше понимание ждет правильно.Он приостанавливает выполнение основной функции.

Ключ в том, что asyncio.create_task() создает задачу и планирует ее.

Итак, функция say_after начинает работать здесь:

task1 = asyncio.create_task(
        say_after(1, 'hello'))

    task2 = asyncio.create_task(
        say_after(2, 'world'))

, а не когда вы ожидаете.

Смотрите здесь: https://docs.python.org/3/library/asyncio-task.html#asyncio.create_task

0 голосов
/ 28 мая 2019

ОК. Ответы @tsuyoku и @Fanto верны. Этот ответ просто дополняет существующие ответы. Для меня важным моментом, который я не мог понять, было выполнение на create_task():

import asyncio
import time

async def say_after(delay, what):
    print('Received {}'.format(what))
    await asyncio.sleep(delay)
    print(what)

async def main():
    task1 = asyncio.create_task(
        say_after(1, 'hello')
    )

    task2 = asyncio.create_task(
        say_after(2, 'world')
    )

    print(f"started at {time.strftime('%X')}")
    await asyncio.sleep(10)

    # Wait until both tasks are completed (should take
    # around 2 seconds.)
    await task2
    print('task 2 finished')
    await task1
    print('task 1 finished')

    print(f"finished at {time.strftime('%X')}")

asyncio.run(main())

печать

started at 10:42:10
Received hello
Received world
hello
world
task 2 finished
task 1 finished
finished at 10:42:20

Первоначальное недоразумение заключается в том, что для выполнения задач требуется немного времени, а исходная распечатка в моем вопросе вводит меня в заблуждение, полагая, что задача не выполняется до оператора await.

...