RAYON_NUM_THREADS=0 不是「不并行」
主线位置:线程池的创建。解析代码逐行在 ThreadPoolBuilder。
flowchart TB
n{"num_threads(n),n > 0"} -->|是| use["用 n,不看环境变量"]
n -->|否| e{"RAYON_NUM_THREADS 按 usize 解析"}
e -->|"正数"| usee["用它"]
e -->|"0"| def["available_parallelism()"]
e -->|"未设或解析失败(abc、空格、-1)"| old{"RAYON_RS_NUM_CPUS 正数?"}
old -->|是| useo["用它"]
old -->|否| def
现象
几种常见的误会:
- 想关掉并行,设了
RAYON_NUM_THREADS=0,结果线程数是核数。 - 部署脚本里写成
RAYON_NUM_THREADS=" 4"或RAYON_NUM_THREADS=4x,没有任何报错,线程数还是核数。 - 设了环境变量,程序里某个
ThreadPoolBuilder::new().num_threads(8).build()的池仍是 8 个线程。 - 在
pool.install里用rayon::current_num_threads()算分块数,得到的是pool的线程数,不是全局池的。
复现
exp-rayon/global-init 的 env_threads(本机 available_parallelism() = 12)打印全局池大小和一个 num_threads(2) 池的大小(ThreadPoolBuilder):
RAYON_NUM_THREADS | RAYON_RS_NUM_CPUS | 全局池 | num_threads(2) 的池 |
|---|---|---|---|
| 未设 | 未设 | 12 | 2 |
4 | 未设 | 4 | 2 |
0 | 未设 | 12 | 2 |
abc / " 4" / -1 / "" | 未设 | 12 | 2 |
| 未设 | 3 | 3 | 2 |
5 | 3 | 5 | 2 |
0 | 3 | 12 | 2 |
abc | 3 | 3 | 2 |
从哪来
num_threads(n)且n > 0:用 n,环境变量不看。RAYON_NUM_THREADS用usize::from_str解析:正数就用;0直接返回默认值;解析失败(非数字、带空格、负数、空串)什么也不说,往下走。- 废弃的
RAYON_RS_NUM_CPUS,只认正数。 available_parallelism(),取不到是 1。
所以 0 的含义是「用默认」,和 num_threads(0) 一致(builder 的默认值就是 0);而写错的值被当成没设,还会让旧变量意外生效(最后一行)。之后 Registry::new 再截到 max_num_threads()(64 位 65535),超出也是静默截断。
current_num_threads() 读的是「调用线程所在的池」,不在任何池里才是全局池(Registry::current_num_threads)。第一次从非 worker 线程调用它,还会用默认配置把全局池建起来(The global thread pool has already been initialized)。
环境变量只在全局池被创建的那一刻和每次 ThreadPoolBuilder::build() 时读取,进程运行中改 std::env::set_var 对已建好的池没有作用。
怎么改
- 要串行:
RAYON_NUM_THREADS=1,不是 0。注意 1 线程时par_iter仍然要进池(从调用线程注入到那一个 worker),从池外调用的固定开销还在(几十个元素的 par_iter 比串行慢几万倍)。 - 校验配置:启动时打印一次
rayon::current_num_threads(),和期望值对比;部署脚本里只写纯数字。 - 库代码别写死
num_threads:私有池写死线程数会让用户的环境变量失效。需要可配置时,自己读环境变量或接收参数。 - 其他读同一个变量的库:candle 的
get_num_threads()也读RAYON_NUM_THREADS,它和 rayon 全局池大小一起变(candle 卷 CPU 后端)。
小结
RAYON_NUM_THREADS=0= 默认(核数);非数字、带空格、负数被静默忽略,并可能让废弃的RAYON_RS_NUM_CPUS生效。num_threads(n > 0)优先于环境变量;current_num_threads()是当前池的线程数。- 要串行设 1;启动时打印实际线程数做校验。
💬 关联讨论
发起讨论加载中...