python asyncios create_task 和 await 函数

F.E*_*F.E 6 python asynchronous

我试图了解 pythons asynico 模块并在https://docs.python.org/3/library/asyncio-task.html#asyncio.create_task 上遇到了以下代码

import time
import asyncio

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('started at', time.strftime('%X'))

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

    print('finished at', time.strftime('%X'))

asyncio.run(main())
Run Code Online (Sandbox Code Playgroud)

事实证明, await task2, (或task1,但不是两者)可以简单地删除,并且代码似乎完全相同。我觉得这很违反直觉,这里发生了什么?感谢您的时间。

Bra*_*mon 6

您提出了三种不同的场景:

  1. 没有await声明(注释掉两者)
  2. 仅使用await task1(注释掉第二个)
  3. 仅使用await task2(注释掉第一个)

这是你的脚本;task2为了说明起见,稍微延长睡眠时间。

# tasktest.py
import time
import asyncio

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(3, 'world'))

    print('started at', time.strftime('%X'))
    await task1
    # await task2
    print('finished at', time.strftime('%X'))

asyncio.run(main())
Run Code Online (Sandbox Code Playgroud)

1. 没有await声明

这是肉asyncio.run()

loop = events.new_event_loop()
try:
    events.set_event_loop(loop)
    loop.set_debug(debug)
    return loop.run_until_complete(main)   # < -----
finally:
    try:
        _cancel_all_tasks(loop)            # < -----
        loop.run_until_complete(loop.shutdown_asyncgens())
    finally:
        events.set_event_loop(None)
        loop.close()
Run Code Online (Sandbox Code Playgroud)

重要的是,循环关心main()是否完成,然后取消与正在运行的事件循环关联的所有其他任务。(每个任务在指定时都绑定到一个事件循环。)

如果main()不带任何await语句定义,则create_task()调度要执行的任务,但main()不等待其中任何一个完成。

2. await task1

设置:

await task1
# await task2
Run Code Online (Sandbox Code Playgroud)

输出:

(base_py37) $ python3 tasktest.py 
started at 11:06:46
hello
finished at 11:06:47
Run Code Online (Sandbox Code Playgroud)

这两个任务都从挂起状态变为运行状态,但只能task1完成,因为main()只等待一个耗时约 1 秒的任务,不足以task2运行。* (注意main()只需要 1 秒。)

3. await task2

设置:

# await task1
await task2
Run Code Online (Sandbox Code Playgroud)

输出:

(base_py37) $ python3 tasktest.py 
started at 11:08:37
hello
world
finished at 11:08:40
Run Code Online (Sandbox Code Playgroud)

这两个任务未决运行搬了,现在都task1task2完整,由于main()对大约需要3秒,足够长的任务都完成运行任务等待。


*这至少适用于我的设置(Mac OSX,...),但正如这里的另一个答案中提到的,在另一个设置上的时间可能会有所不同,如果任务运行时间相似,两者都可能会运行在像案例#2 这样的地方。