- Authors

- Name
- qiaoshilei
- GitHub1395291968@qq.com
1. 问题背景:豪横的 180 核服务器反而跑不起来?
最近在部署 FunASR 语音识别服务时,遇到了一件非常"反直觉"的事情。我使用了一台配置极高的服务器,拥有 180 个 CPU 核心。本以为这样的硬件能带来极致的推理速度,结果服务启动并在高并发压测下,直接崩溃了。
故障现象
具体的故障现象如下:
报错信息:
控制台疯狂输出 OpenMP 错误:
libgomp: Thread creation failed: Resource temporarily unavailable
系统指标:
- CPU 使用率:显示为 14000%(正常应该是 100% * 核心数,但这里显示异常高)
- 内存:快速增长直至 OOM(Out Of Memory) killer 触发
- 服务状态:进程卡死,无法响应请求
问题定位过程
2.1. 初步排查
最初怀疑是内存泄漏,但通过内存分析工具(如 valgrind、gdb)检查,并未发现明显的泄漏点。
2.2. 深入分析
通过 htop 命令观察,发现单个进程创建了上百个线程,而系统中同时运行着多个这样的进程。在 180 核的服务器上,理论上可以支持大量线程,但问题在于:
- 线程爆炸:每个 FunASR 进程默认会根据 CPU 核心数创建大量线程
- 上下文切换开销:当线程数远超物理核心数时,大量的上下文切换导致 CPU 时间浪费在调度上
- 内存压力:每个线程都需要分配栈空间,大量线程导致内存快速耗尽
2.3. 根本原因
FunASR 基于 PyTorch,而 PyTorch 默认使用 OpenMP 进行并行计算。OpenMP 会尝试创建与 CPU 核心数相等的线程数,但在多进程环境下,如果每个进程都这样做,总线程数会呈指数级增长。
解决方案
3.1. 限制线程数
通过设置环境变量或代码配置,限制每个进程的线程数:
import torch
import os
# 方法1:设置全局线程数
torch.set_num_threads(4) # 限制为4个线程
# 方法2:通过环境变量
os.environ["OMP_NUM_THREADS"] = "4"
os.environ["MKL_NUM_THREADS"] = "4"
3.2. 配置优化
根据服务器实际核心数和进程数,合理分配线程数:
# 假设有180核,部署10个进程
# 每个进程分配 180/10 = 18个线程,但实际可以更保守
torch.set_num_threads(8) # 每个进程使用8个线程
3.3. 效果验证
配置后重新部署:
- CPU 使用率:恢复到正常水平,不再出现虚高的 14000%
- 内存占用:稳定在合理范围
- QPS 提升:由于减少了昂贵的上下文切换开销,整体服务的吞吐量(QPS)反而提升了,延迟也更加稳定
避坑总结
在 180核 这种怪兽级服务器上跑深度学习推理,千万不要迷信默认配置。
- 现象:CPU 几千/几万%,报 libgomp 错误,服务卡死。
- 本质:线程爆炸 (Thread Explosion)。
- 对策:
torch.set_num_threads()是必须配置的参数。