单机并行
说明路径搜索、切片任务分块和矩阵乘法的并行方式,以及线程数与实际 CPU 使用量的区别。
本页目录
一次调用中的并行搜索
Light / Heavy 的编译库接收调用方的 Rayon 线程池宽度,并在一次调用内安排并行搜索。无需在调用外再写种子循环;seed 指定本次搜索的基础种子。使用 Heavy给出单次调用示例。
例如 RAYON_NUM_THREADS=8 设置 8 个工作线程。它不预留 8 个物理核,也不固定进程 affinity;实际 CPU 使用量由可并行任务、系统调度和其他负载共同决定。内部起点数与候选调度不是公开返回字段。
推荐线程配置
Light 和 Heavy 建议从 8 个工作线程开始。需要增加搜索投入且有足够 CPU 资源时,可使用 16、24 或 32 个线程。当前实现按每 8 个线程增加一个独立搜索起点:
RAYON_NUM_THREADS |
独立搜索起点数 |
|---|---|
8 |
1 |
16 |
2 |
24 |
3 |
32 |
4 |
各起点使用不同种子,由一次调用并行调度,最后按本次优化目标选择结果。它们共享总线程池,不是顺序执行两轮或三轮,也不为每个起点固定绑定 8 个核心。基础种子通过 seed 指定,其余种子由库派生。
在程序启动前设置线程数。例如,有 24 个可用物理核心时,可设置:
RAYON_NUM_THREADS=24 python plan.py
8 是建议的起始配置,不是强制的最小值,也不是对所有网络都最快的配置。未显式设置线程数时,由 Rayon 运行时决定,不固定为 8。更多起点增加搜索工作量,可能改善路径质量,不表示单次搜索按比例加速。
并行单位
| 位置 | 可并行工作 | 仍需顺序或同步的部分 |
|---|---|---|
| Light / Heavy | 多个独立起点及每个起点内的搜索任务 | 搜索过程中的依赖与结果汇总 |
| random_greedy | 多次完整搜索 | 单次搜索中的贪心步骤 |
| bisect | 多次独立划分 | 一次递归划分的父子调用 |
| order_dp | 长度相同的不同区间 | 区间长度从小到大推进 |
| anneal_paths / treesa_path | 多条独立搜索链 | 单条链内的局部旋转 |
| temper_path(s) | 同一轮中各副本的局部搜索 | 轮末相邻副本交换,以及下一轮的开始 |
| 原生切片执行 | 多组切片任务 | 每组内部的求和顺序,以及各组部分和的合并顺序 |
| matrixmultiply mt | 单个 GEMM 内部线程 | 由可选 Cargo feature 和线程上限控制 |
对公开低层算法,并行对象的数量给出阶段并行度上限;给一个阶段更多线程,不代表它能持续占用同样数量的 CPU 核。单独调用低层算法时,不会额外采用 Light 和 Heavy 的独立起点调度规则。
线程池与嵌套并行
RAYON_NUM_THREADS=8 cargo run --release --bin tnpath -- \
network.json --method auto --preset heavy --seed 0
RAYON_NUM_THREADS=8 MATMUL_NUM_THREADS=1 tnexec \
--net network.json --load-path plan.json
| 控制项 | 作用域 |
|---|---|
| RAYON_NUM_THREADS | Light / Heavy 路径搜索、公开低层算法和原生切片任务分块 |
| MATMUL_NUM_THREADS | 启用 matrixmultiply mt feature 时的单个 GEMM 内线程 |
| CPU affinity / launcher binding | 进程实际可以运行在哪些 CPU 上 |
外层 Rayon 与内层 GEMM 同时使用多线程,可能使可运行线程数超过可用 CPU 数量,产生过量订阅(oversubscription)。tnexec 在外层切片分块多于 1、且调用者未设置 MATMUL_NUM_THREADS 时,将它设为 1;已有设置不会被覆盖。默认 Python wheel 不启用 matrixmultiply 的可选线程池。
线程数、工作量和结果
对低层固定 ntrials、chains、rounds 或 moves 的调用,增加线程主要改变完成这些工作所需的实际时间。Light 和 Heavy 的搜索工作量可能随线程设置变化,因此比较不同线程数时,应同时记录实际耗时与路径质量,不能直接视为固定工作量的线程加速。
| 比较问题 | 需要固定的量 |
|---|---|
| 固定工作量的线程加速 | 同一入口、trial/chain/round 数、seed、objective 和输出验证 |
| 不同资源配置下的 Light / Heavy 结果 | 记录配置、实际耗时和最终路径指标;工作量不同时,不能作为固定工作量的强缩放测试 |
| 设置 max_time 后的结果 | 外部总时间上限、重复次数和实际完成工作量;检查点触发时间会受运行时序影响 |
| 切片执行加速 | 同一 path、sliced legs、dtype、chunk 规则和后端 |
线程池宽度不是物理核数,也不是实际平均用核。只写 RAYON_NUM_THREADS=8 不能证明阶段使用了 8 个物理核。
并行运行时需要记录的信息
阶段平均 CPU 使用量可以用 process CPU time / wall time 估计。例如比值为 2 表示该窗口内平均每秒消耗 2 个 CPU 秒,不能单独证明使用了多少物理核。等待、内存带宽瓶颈或任务不足都会使该比值低于线程池宽度。
- 记录 CPU affinity、物理核与 SMT 映射,而不只记录逻辑线程数。
- 记录 Rayon worker count,以及是否启用 matrixmultiply mt。
- 记录进程 CPU 时间、墙钟时间、RSS,以及测量的起止时刻。
- 单独测试公开低层算法时,记录 trial、chain、replica 或 slice chunk 的数量;Light / Heavy 的内部候选记录不通过公开接口返回。
- 共享服务器上同时运行多个进程,可以提高单位时间内完成的任务数;这不等于缩短单个进程完成同一任务所需的时间。