【发布时间】:2022-11-06 22:30:22
【问题描述】:
asyncio.create_task() 的文档指出以下警告:
重要的:保存对该函数结果的引用,以避免任务在执行过程中消失。 (source)
我的问题是:这是真的吗?
我有几个 IO 绑定的“即发即忘”任务,我想使用
asyncio通过使用asyncio.create_task()将它们提交到事件循环来同时运行这些任务。但是,我并不真正关心协程的返回值,或者即使它们运行成功,只关心它们做最终运行。一个用例是将“昂贵”计算中的数据写回 Redis 数据库。如果 Redis 可用,那就太好了。如果没有,哦,好吧,没有伤害。这就是为什么我不想/不需要await那些任务。这是一个通用示例:
import asyncio async def fire_and_forget_coro(): """Some random coroutine waiting for IO to complete.""" print('in fire_and_forget_coro()') await asyncio.sleep(1.0) print('fire_and_forget_coro() done') async def async_main(): """Main entry point of asyncio application.""" print('in async_main()') n = 3 for _ in range(n): # create_task() does not block, returns immediately. # Note: We do NOT save a reference to the submitted task here! asyncio.create_task(fire_and_forget_coro(), name='fire_and_forget_coro') print('awaiting sleep in async_main()') await asycnio.sleep(2.0) # <-- note this line print('sleeping done in async_main()') print('async_main() done.') # all references of tasks we *might* have go out of scope when returning from this coroutine! return if __name__ == '__main__': asyncio.run(async_main())输出:
in async_main() awaiting sleep in async_main() in fire_and_forget_coro() in fire_and_forget_coro() in fire_and_forget_coro() fire_and_forget_coro() done fire_and_forget_coro() done fire_and_forget_coro() done sleeping done in async_main() async_main() done.在注释掉
await asyncio.sleep()行时,我们永远不会看到fire_and_forget_coro()完成。这是意料之中的:当以asyncio.run()开始的事件循环关闭时,将不再执行任务。但似乎只要事件循环仍在运行,所有任务都会得到处理,即使我从未明确创建对它们的引用。这对我来说似乎是合乎逻辑的,因为事件循环本身必须参考所有计划任务以运行它们。我们甚至可以使用asyncio.all_tasks()获取它们!所以我思考只要提交给它的事件循环仍在运行,我就可以相信 Python 对每个计划任务至少有一个强引用,因此我不必自己管理引用。但我想在这里发表第二意见。我是对的还是有我还没有认识到的陷阱?
如果我是对的,为什么文档中有明确的警告?如果你不保留对它的引用,那么通常的 Python 事情就是垃圾收集。是否存在没有正在运行的事件循环但仍有一些任务对象要引用的情况?也许在手动创建事件循环时(从未这样做过)?
【问题讨论】:
-
await asycnio.sleep(2.0)asyncio 错字
标签: python python-asyncio