python-asyncio - 了解异步等待行为
问题描述
我有以下示例代码:
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
是否有具体原因说明为什么会发生这种情况以及我如何才能达到预期的结果?
解决方案
等待协程的全部意义在于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())
推荐阅读
- java - 将枚举和环境变量传递给 SequenceStyleGenerator 生成字符串前缀序列的方法
- java - Java JAXB 编组:如何避免在使用 XMLAdapter 对元素进行编组期间添加 XmlElement
- json - python烧瓶的CURL响应与LOCAL和Container不同
- vue.js - 从 Vue2 中的另一个组件更新一个组件
- python - For循环得到错误说(奇数 - 奇数)/ 2是一个浮点数
- python - Docker 容器中的 Django 单元测试:ModuleNotFoundError: No module named 'code.x'; “代码”不是一个包
- python - 我的 TCP 聊天室代码使我的笔记本电脑挂起,当我尝试在另一台电脑上运行客户端脚本时它也不起作用
- laravel - Laravel Fortify/Sanctum:在未登录的情况下重新发送验证邮件
- javascript - 将内部数组从地图合并为一个的干净方法是什么?
- css - 带有 CSS Grid 的流畅照片库