无法捕获关闭asyncio事件循环引发的RuntimeError如何解决?
解决asyncio信号处理中RuntimeError捕获失败的问题
问题原因
你当前的try-except捕获不到错误,是因为RuntimeError不是在self.loop.stop()执行时直接抛出的——这个错误是asyncio.run()内部的run_until_complete()方法抛出的。当你在信号处理函数里调用loop.stop(),事件循环提前终止,但asyncio.run还在等待传入的主协程完成,因此会触发这个错误,而它的抛出栈不在你的signal_handler的try块范围内,所以捕获无效。
解决方案
方案1:在asyncio.run调用处捕获错误
直接在调用asyncio.run的代码外层添加try-except,就能捕获到这个RuntimeError:
def main(self, link): try: asyncio.run(video.get_file(obj.metadata['name']+"_v."+obj.default_video_stream[1], obj.default_video_stream[0])) except RuntimeError as e: if "Event loop stopped before Future completed" in str(e): print('SIGINT or SIGTSTP raised') print("cleaning and exiting") else: # 处理其他类型的RuntimeError raise
方案2:优雅终止主任务(推荐)
不要直接调用loop.stop(),而是取消当前运行的主协程,等待清理完成后再停止循环,这样可以避免触发这个RuntimeError:
async def signal_handler(self): print('SIGINT or SIGTSTP raised') # 获取当前运行的主任务 main_task = asyncio.current_task() if main_task: main_task.cancel() # 执行你的清理协程 # await self.cleanup_coroutine() # 等待任务取消完成后停止循环 await asyncio.sleep(0.1) self.loop.stop()
同时,在你的主协程get_file里要处理CancelledError:
async def get_file(self, filename, stream): try: # 你的原有逻辑 ... except asyncio.CancelledError: # 可选:在这里做局部清理 print("任务被取消,执行局部清理") raise # 必须重新抛出,让asyncio处理取消流程
这样修改后,信号触发时会主动取消主任务,清理完成后再停止循环,asyncio.run会正常处理取消流程,不会抛出那个RuntimeError。
内容的提问来源于stack exchange,提问作者GreninjaShuriken4
相关产品推荐
相关产品推荐

