Python async/await 执行时间的差异

Jib*_*ews 2 python python-3.x async-await python-asyncio

我正在使用 async io 对两种执行方法进行计时

情况1:

async def test():    
    print(f"started at {time.strftime('%X')}")
    await asyncio.create_task(say_after(2, 'hello'))
    await asyncio.create_task(say_after(4, 'world'))    
    print(f"finished at {time.strftime('%X')}")
Run Code Online (Sandbox Code Playgroud)

它的回应是:

started at 12:31:05
hello
world
finished at 12:31:11
Run Code Online (Sandbox Code Playgroud)

总共6秒

案例2:

async def test():    
    print(f"started at {time.strftime('%X')}")
    t1=asyncio.create_task(say_after(2, 'hello'))
    t2= asyncio.create_task(say_after(4, 'world'))    
    await t1
    await t2
    print(f"finished at {time.strftime('%X')}")
Run Code Online (Sandbox Code Playgroud)

它的回应是:

started at 12:31:05
hello
world
finished at 12:31:09
Run Code Online (Sandbox Code Playgroud)

总共4秒

为什么会这样呢?

Mar*_*ers 6

在第一个示例中,您在询问时创建,等待它完成,然后创建另一个任务,并等待另一个任务完成。您正在按顺序执行任务。

在第二个示例中,您将创建两个任务,然后在创建这两个任务后,等待这两个任务完成。您正在同时执行这些任务。

这些任务需要 2 + 4 = 6 秒来依次执行,但是当连续执行时,您只需等待 4 秒即可完成第二个较长的任务,而较短的 2 秒任务会在此之前完成一段时间:

# sequentially

| start task 1
V
+-------------+
| 2 seconds   |
+-------------+
              ^
await returns |

                | start task 2
                V
                +--------------------------+
                | 4 seconds                |
                +--------------------------+
                                           ^
                             await returns |

# consecutively

| start task 1
V
+-------------+
| 2 seconds   |
+-------------+
              ^
await returns |

| start task 2
V
+--------------------------+
| 4 seconds                |
+--------------------------+
                           ^
             await returns |
Run Code Online (Sandbox Code Playgroud)

区别在于调用asyncio.create_task()不是立即等待任务,因为await task在任务完成之前不会完成。

Awaitables文档任务部分有一个示例:

async def main():
    # Schedule nested() to run soon concurrently
    # with "main()".
    task = asyncio.create_task(nested())

    # "task" can now be used to cancel "nested()", or
    # can simply be awaited to wait until it is complete:
    await task
Run Code Online (Sandbox Code Playgroud)

请注意,Schedulenested() 很快就会与“main()”同时运行或者可以简单地等待,直到它完成注释。

任务是专门的Future子类,因此此处的文档asyncio.Future也相关:

未来是一个等待的对象。协程可以等待 Future 对象,直到它们有结果或设置异常,或者直到它们被取消。