首页 > 解决方案 > Python async/await 执行时间的差异

问题描述

我正在使用异步 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')}")

它的响应是:

started at 12:31:05
hello
world
finished at 12:31:11

一共6秒

案例二:

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')}")

它的响应是:

started at 12:31:05
hello
world
finished at 12:31:09

一共4秒

为什么会这样?

标签: pythonpython-3.xasync-awaitpython-asyncio

解决方案


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

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

这些任务一个接一个地执行需要 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 |

不同之处在于调用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

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

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

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


推荐阅读