TensorFlow训练结束后程序终止出现无溯源OSError,如何定位问题根源
异常本质说明
这个异常是Python多进程池Pool的析构方法触发的,发生在程序退出、资源回收阶段,所以常规报错栈只会打印标准库的调用路径,不会关联到你的业务代码位置,本身不会影响程序正常功能,只是退出时的报错提示。
定位方法
- 打猴子补丁记录进程池创建位置:在程序入口处添加如下代码,所有
Pool实例创建时会记录调用栈,析构出错时就会打印对应的创建位置,帮你定位到业务代码中创建未正确释放的进程池的位置:
import traceback from multiprocessing.pool import Pool original_init = Pool.__init__ original_del = Pool.__del__ # 给每个Pool实例加创建栈属性 def tracked_init(self, *args, **kwargs): self._init_stack = traceback.format_stack() original_init(self, *args, **kwargs) # 析构出错时打印创建栈 def safe_del(self): try: original_del(self) except OSError as e: if e.errno == 9: print("="*50) print("Bad file descriptor error from Pool created at:") print("".join(self._init_stack)) print("="*50) else: raise Pool.__init__ = tracked_init Pool.__del__ = safe_del
- 优先排查两类常见的进程池创建场景:
- 业务代码中显式创建的
multiprocessing.Pool,检查是否没有在退出前调用close()+join(),推荐直接改用with上下文管理器写法,会自动处理资源释放:
# 正确写法示例 from multiprocessing import Pool with Pool(processes=4) as pool: # 你的并行逻辑 res = pool.map(your_func, your_args) # 退出with块后自动释放资源,不会留到析构阶段报错- TensorFlow相关的隐式进程池:如果你的代码没有手动创建进程池,大概率是
tf.data数据加载模块内部创建的多进程实例,旧版本TensorFlow存在这类资源释放的bug,升级到最新稳定版即可解决,也可以尝试将数据加载的num_parallel_calls参数调整为小于CPU核心数的固定值,或设置为tf.data.AUTOTUNE,避免资源抢占。
- 业务代码中显式创建的
临时屏蔽方案
如果不需要定位,只是想屏蔽这个不影响功能的报错,直接使用上述safe_del补丁跳过析构时的OSError即可。
内容的提问来源于stack exchange,提问作者Stefan Falk
相关产品推荐
相关产品推荐

