Python循环二次迭代报错:RuntimeWarning协程'to_thread'未被等待
问题原因分析与解决方案
报错核心原因
asyncio.get_event_loop()并非每次调用都会创建新循环:在同一线程内,它会返回已存在的默认事件循环,只有当前线程没有默认循环时才会新建。- 第一次循环中你调用
loop.close()关闭了默认循环,第二次循环再调用get_event_loop()时,返回的还是那个已关闭的循环。此时用它创建任务(比如asyncio.gather内部会调用loop.create_task)就会触发RuntimeError: Event loop is closed。 - 至于
RuntimeWarning: coroutine 'to_thread' was never awaited,是因为第二次循环里创建的to_thread协程绑定在已关闭的循环上,根本没机会被执行,最终成为未被await的协程。
正确处理方式
方式一:复用同一个事件循环(推荐)
把循环的创建和关闭移到外层,避免重复销毁重建:
import asyncio def some_func(number): print('task number:', number) return number def start(): loop = asyncio.get_event_loop() try: for r in range(2): print('r:', r) tasks = [asyncio.to_thread(some_func, i) for i in range(5)] responses = asyncio.gather(*tasks, return_exceptions=True) results = loop.run_until_complete(responses) print('results:', results) finally: loop.close() if __name__ == '__main__': start()
方式二:每次循环手动创建新循环(不推荐,开销较大)
如果一定要每次用新循环,需要手动创建并设置为当前线程的默认循环:
import asyncio def some_func(number): print('task number:', number) return number def start(): for r in range(2): print('r:', r) # 手动创建新循环并设置为当前线程默认 loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) try: tasks = [asyncio.to_thread(some_func, i) for i in range(5)] responses = asyncio.gather(*tasks, return_exceptions=True) results = loop.run_until_complete(responses) print('results:', results) finally: loop.close() if __name__ == '__main__': start()
方式三:用asyncio.run()简化管理(Python 3.7+推荐)
asyncio.run()会自动处理循环的创建、运行和关闭,代码更简洁:
import asyncio def some_func(number): print('task number:', number) return number async def run_batch(): tasks = [asyncio.to_thread(some_func, i) for i in range(5)] return await asyncio.gather(*tasks, return_exceptions=True) def start(): for r in range(2): print('r:', r) results = asyncio.run(run_batch()) print('results:', results) if __name__ == '__main__': start()
内容的提问来源于stack exchange,提问作者TitanFighter
相关产品推荐
相关产品推荐

