Как python обойти мой предыдущий код, чтобы сначала запустить более поздние коды? - PullRequest
1 голос
/ 11 марта 2020
import asyncio
import time


async def func():
    print('task start')
    await asyncio.sleep(10)
    print('task end')


async def main():
    task1 = asyncio.create_task(func())
    task2 = asyncio.create_task(func())
    task3 = asyncio.create_task(func())
    task4 = asyncio.create_task(func())
    s = time.monotonic()
    print('main start', time.monotonic() - s)
    await task1
    print('main continue', time.monotonic() - s)
    await task2
    print('main continue', time.monotonic() - s)
    await task3
    print('main continue', time.monotonic() - s)
    await task4
    print('main end', time.monotonic() - s)


asyncio.run(main())

Этот код дает следующие результаты:

main start 0.0
task start
task start
task start
task start
task end
task end
task end
task end
main continue 10.0
main continue 10.0
main continue 10.0
main end

Но как это возможно, python обошел мои предыдущие вызовы печати, сначала запустите awaitables, а затем go, чтобы сделать печать звонки, как мне это понять?

Ответы [ 2 ]

1 голос
/ 11 марта 2020

Все ваши задания спят 10 секунд, затем продолжают и заканчивают sh почти мгновенно. Таким образом, все вызовы await будут разблокированы одновременно, так как после выполнения задачи 1 все задачи также будут завершены.

Вы правы в том смысле, что технически вы могли переплести отпечатки между task end и main continue но я думаю, что это деталь реализации, в которой все выглядит сгруппированным.

Я думаю, что вы можете лучше понять, что происходит, используя этот измененный скрипт:

import asyncio
import time


async def func(task_nb, wait):
    print('[%s] task start' % task_nb)
    await asyncio.sleep(wait)
    print('[%s] task end' % task_nb)


async def main():
    task1 = asyncio.create_task(func(1, 1))
    task2 = asyncio.create_task(func(2, 5))
    task3 = asyncio.create_task(func(3, 7))
    task4 = asyncio.create_task(func(4, 2))
    s = time.monotonic()
    print('main start', time.monotonic() - s)
    await task1
    print('main continue', time.monotonic() - s)
    await task2
    print('main continue', time.monotonic() - s)
    await task3
    print('main continue', time.monotonic() - s)
    await task4
    print('main end', time.monotonic() - s)


asyncio.run(main())

У вас будет более интересное await поведение:

main start 1.81000359589234e-07
[1] task start
[2] task start
[3] task start
[4] task start
[1] task end
main continue 1.0019499360005284
[4] task end
[2] task end
main continue 5.001785704000213
[3] task end
main continue 7.003587035000237
main end 7.003632674000073
0 голосов
/ 11 марта 2020

Ваш код делает то, что должен делать в соответствии со спецификацией asyncio, но, возможно, вы неправильно понимаете, что такое «задача».

Из документов:

asyncio.create_task(coro, *, name=None)

Оберните сопрограмму coro в задание и запланируйте его выполнение. Верните объект Task.

Это означает, что, поскольку вы создали 4 задачи в начале своей основной программы, все они запланированы для запуска, начиная с того же времени. И поэтому все они печатают task start вместе, а затем печатают task end вместе, и в этот момент все ваши await мгновенно падают, когда все задачи выполнены одновременно (через 10 секунд). Итак, наконец вы видите main continue 10.0 3 раза.

Попробуйте этот код, я думаю, он будет иметь ожидаемое вами поведение.

async def main():
    task1 = func()
    task2 = func()
    task3 = func()
    task4 = func()
    ...
...