在asyncio.run()外部等待asyncio futures的运行机制疑问
关于asyncio.run()外部等待Future的疑问
我在某代码库中遇到如下模式,这打破了我对asyncio工作机制的认知。我们有一个函数会await一部分futures集合,返回另一部分耗时更长的futures集合,随后在asyncio.run()外部等待这部分返回的futures。我不确定这些后续的futures在asyncio.run()外无事件循环的情况下如何获取CPU时间,是否在调用f.result()时它们才有机会运行/完成?
async def foo(): futures_a = ... futures_b = ... await asyncio.gather(*futures_a) return futures_b async def main(): tasks = set() tasks.add(asyncio.create_task(foo())) tasks.add(asyncio.create_task(foo())) tasks.add(asyncio.create_task(foo())) return await asyncio.gather(*tasks) pending_futures = asyncio.run(main()) for f in pending_futures: f.result()
解答
首先明确:这些返回的futures_b不是在调用f.result()时才开始运行,它们的执行逻辑取决于自身类型:
1. 如果futures_b是concurrent.futures.Future(比如通过loop.run_in_executor()创建的线程/进程任务)
这类Future的执行完全不依赖asyncio事件循环,任务会在独立的线程或进程池中运行。当foo()创建它们时,后台任务就已经启动了——哪怕await futures_a在等待,这些线程/进程任务也会并行执行。
当asyncio.run()结束、事件循环关闭后,这些后台任务仍会继续运行。调用f.result()只是阻塞当前主线程,等待后台任务完成并返回结果,此时不需要asyncio事件循环参与。
2. 如果futures_b是asyncio.Task(通过asyncio.create_task()创建的异步任务)
这种情况代码逻辑是有问题的:
asyncio.Task的执行完全依赖绑定的事件循环。当asyncio.run()结束时,它会关闭内部创建的事件循环,未完成的Task会被暂停(甚至可能被标记为取消)。- 此时调用
f.result()会一直阻塞,因为没有事件循环驱动Task继续执行,最终要么抛出CancelledError,要么永远无法得到结果。
所以你看到的这个模式能正常工作,前提是futures_b是不依赖asyncio事件循环的线程/进程池Future。你之前的误解在于混淆了asyncio Task和普通Future的执行依赖——前者必须靠事件循环调度,后者靠线程/进程池独立运行。
内容的提问来源于stack exchange,提问作者Milad
相关产品推荐
相关产品推荐

