多线程 Python 服务增加线程却不增加吞吐,CPU 只跑满一个核。
CPU 密集接口在并发升高后延迟不降、QPS 不涨;top -H 显示只有一个线程接近 100%,其余线程大量时间在等待。常见于把纯 Python 计算塞进 ThreadPoolExecutor 或 threading 的服务。
先确认是 CPU 密集还是 I/O 密集,再看线程都卡在哪里:
python -VV
python -c "import sys, sysconfig; print(getattr(sys, '_is_gil_enabled', lambda: 'n/a')()); print(sysconfig.get_config_var('Py_GIL_DISABLED'))"
top -H -p <PID>
ps -L -o pid,tid,pcpu,stat,comm -p <PID> | sort -k3 -nr | head
py-spy top --pid <PID>
py-spy dump --pid <PID> --gil
py-spy dump --gil 能看到线程等待 GIL 的状态;若大量栈停在 take_gil 或解释器求值循环,基本可以确认 GIL 争用。再看系统调用占比:
timeout 10 strace -f -c -p <PID>
perf top -p <PID>
易误判:单核打满不一定是 GIL —— 也可能是代码本来就是单线程路径、全局锁或某个不释放 GIL 的 C 调用。反过来,3.13 free-threaded 构建在导入未声明支持自由线程的 C 扩展时会自动重新启用 GIL,sys._is_gil_enabled() 返回 True 就说明仍在 GIL 下运行。
ProcessPoolExecutor/multiprocessing,或把热点下沉到 numpy、Cython、Rust 扩展。asyncio,避免每连接一个线程。Py_BEGIN_ALLOW_THREADS 包裹阻塞段。-X gil=0)。spawn 启动子进程,避免 fork 继承损坏的锁状态。sys.setswitchinterval() 只作为微调,必须用 p99 和吞吐共同验证。-H 查看每线程 CPUpy-spy dump --gil 显示大量线程等待 GIL,下一步该改什么?