首页 > 解决方案 > 了解异步等待行为

问题描述

我有以下示例代码:

from datetime import datetime
import asyncio

async def h():
    print("h() has started")
    await asyncio.sleep(5)
    print("h() has ended")

async def main():
    print("{}: start of program".format(datetime.now()))
    await h()
    print("{}: end of program".format(datetime.now()))

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())

我本来期望(并希望代码的输出)是以下几行:

2020-03-03 17:31:25.379742: start of program
h() has started
2020-03-03 17:31:30.384977: end of program
h() has ended

但是我有以下输出:

2020-03-03 17:31:25.379742: start of program
h() has started
h() has ended
2020-03-03 17:31:30.384977: end of program

是否有具体原因说明为什么会发生这种情况以及我如何才能达到预期的结果?

标签: python-asyncio

解决方案


等待协程的全部意义在于h()等待完成,并且(在有意义的地方)访问它的返回值。例如,line = await stream.readline()暂停当前协程直到readline()完成,然后将结果提供给line.

如果要h()在后台运行,可以asyncio.create_task改用。但它仍然不会产生所需的输出,因为run_until_complete(main())只等待main()完成,而忽略它可能产生的其他任务。(它还返回协程的返回值,很像同步的等价物await。)

如果您想等待其他任务,您必须明确说明。也许是这样的:

async def main():
    bgtasks = []
    print("{}: start of program".format(datetime.now()))
    bgtasks.append(asyncio.create_task(h()))
    print("{}: end of program".format(datetime.now()))
    return bgtasks

async def run_everything():
    more_tasks = await main()
    await asyncio.gather(*more_tasks)

if __name__ == '__main__':
    asyncio.run(run_everything())

推荐阅读