You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为什么操作系统层面的线程数远多于Python代码实际创建的线程数?

问题原因与排查方案

线程数不一致的核心原因

你看到的差异主要来自两类线程,Python官方的threading模块只会统计通过threading.Thread接口创建、且尚未退出的活跃线程,剩下的2类线程不会被统计到:

  • 未被回收的僵尸线程:如果你创建的非daemon线程运行结束后,主线程没有主动调用join()方法回收资源,Python层会将该线程标记为非活跃,从active_count中移除,但操作系统层面的线程描述符资源不会被释放,会以僵尸/退出状态保留,ps命令仍然能统计到这些已经停止运行的非活跃线程。
  • 底层依赖创建的非Python托管线程:你用到的C扩展、第三方库(比如numpy、PyTorch、数据库驱动、消息队列客户端)会直接调用系统接口pthread_create创建线程,这些线程没有在Python的threading模块注册,所以完全不会被active_count、enumerate统计,这类线程可能是闲置的线程池 worker,也可能是正在运行的活跃线程。

剩余线程的状态判断

绝大多数未回收的僵尸线程都处于非活跃状态,底层依赖创建的线程大部分是闲置等待任务的非活跃线程,只有少部分是正在处理任务的活跃线程。
你可以执行以下命令直接查看所有线程的状态:

ps -T -p <替换为你的进程PID> -o tid,state,comm

输出中state字段对应状态:

  • Z:僵尸状态,完全非活跃
  • S:休眠闲置状态,非活跃
  • R:正在运行状态,活跃

查询线程对应函数名的方法

针对僵尸线程

这类线程已经退出运行,无法直接查询到原始执行的函数名,你可以通过以下验证方法确认是否是未回收导致的:
创建线程时设置daemon=True,线程结束后会自动释放所有资源:

thread1 = threading.Thread(target=foo, args=(arg1,), daemon=True)
thread1.start()

或者在线程任务处理完成后主动调用join()回收,再观察操作系统统计的线程数是否回归正常,即可定位是不是僵尸线程导致的数量暴涨。

针对非僵尸的非托管线程

你可以通过调试工具直接抓取所有线程的调用栈:

  1. 用gdb附着进程查询全量调用栈
    安装对应依赖后执行:
    gdb -p <替换为你的进程PID>
    
    进入gdb交互界面后依次执行:
    info threads # 列出所有线程ID和基础状态
    thread apply all bt # 打印所有线程的完整调用栈,包含C函数和Python函数
    
  2. 用py-spy采样调用栈
    安装py-spy后执行以下命令,采样10秒内所有线程的运行栈:
    py-spy record -p <替换为你的进程PID> --duration 10
    
    不管是Python托管还是底层创建的线程,都能抓到对应的执行函数。

内容的提问来源于stack exchange,提问作者texasraj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 23:48:00