科技 · 实用指南
Python 警告“resource_tracker: leaked semaphore objects”?隐藏前先找到失效持有者
这条退出警告是清理症状,不是根因。先保留首个异常,列出每个进程创建的信号量,再证明 close、join 与 unlink 的正常顺序。

解释器关闭时,resource tracker 仍保存已登记名称就会发出警告。它不会直接告诉你哪个库创建了资源,也不证明最后一行就是根因;被信号杀死的子进程、初始化失败、未关闭的进程池、未排空的队列或重复 unlink 都可能留下同样警告。
从首个异常和持有者台账开始。记录 Python 版本与启动方式,每次只保留一种资源构造器,证明每个子进程的退出及父进程的 close、shutdown、join、unlink 路径;只有生命周期已被证实时,才讨论是否过滤警告。
先保存首个故障,不要只看最后警告
保存完整 stderr 和退出状态,找到 resource-tracker 行之前最早的 traceback、信号、initializer 失败、超时、取消或强制终止。最后警告可能只是次生清理。
记录 Python 构建、操作系统、启动方式、父子 PID、库版本,以及进程是正常返回、抛错、取消还是被杀。不要先过滤 UserWarning。
列出构造器并分配资源持有者
检查应用与依赖边界中的 multiprocessing.Pool、Process、Queue、Lock、Semaphore、ProcessPoolExecutor、SharedMemory、joblib 或数据加载 worker。记录构造位置、所属进程以及负责关闭或 unlink 的作用域。
需要 spawn-safe import 的平台应把进程创建放进 main guard,但不要把它当通用修复;import 时创建资源、initializer 失败或库内部进程池仍有不同原因。
先证明正常退出,再测试崩溃分支
优先使用上下文管理器;否则先关闭进程池使其停止接收任务,再 join;关闭 executor;生产者结束后关闭队列,并按文档 join feeder thread;SharedMemory 由约定的单一持有者 unlink 一次。
基线运行不要 terminate、kill、os._exit、突然停容器或让测试超时。Python 文档明确指出强制终止可能留下共享资源、锁、管道和队列。
区分真实遗留对象与 tracker 记账
把程序缩减到一个构造器和一个子进程,并记录创建、子进程退出、close、join、unlink 与解释器关闭顺序。若警告消失,再逐层加入库,直到所有权发生变化。
仅在 Linux 上,/dev/shm 可作为 POSIX 命名对象的辅助证据;它不是安全删除清单,其他平台也不同。无法绑定到已停止进程和正式清理持有者的名称不能删除。
测试受支持版本与竞态分支
若生命周期正确,在当前受支持的补丁版本重现最小脚本。CPython issue 显示,initializer 失败、重入清理和重复 unlink 竞态在特定版本或测试中都可能产生相似警告。
不要为了安静而把私有 unregister 调用粘进生产。先确认是重复清理、完全没有清理,还是可在特定版本复现的问题。
用无警告、无遗留对象的运行收尾
收尾标准是:每个子进程退出明确,父进程关闭并 join 所有资源,SharedMemory 只有一个 unlink 持有者,解释器关闭不再产生新警告。还要在原 service manager 或 CI 取消路径重复测试。
只有完成上述证明后,才可为已知无害的第三方警告设置窄过滤,并记录版本、最小复现、上游 issue 与移除条件。
