4.5 KiB
并行化
本文件记录并行化的判定标准、提供的接口,以及实测结果。跨层的单位与坐标约定见 单位与坐标约定,分层边界见 分层边界。
为什么不引入线程池
工作区禁止任何第三方 crate,因此没有 rayon 这样的线程池可用。也不需要:
工作区中值得多核的运算,无一例外都是逐元素独立的循环,用标准库的
std::thread::scope 就能直接表达。
作用域线程按引用借用数据,调用方无需 Arc 即可共享一个切片或一个只读对象;
作用域结束前会 join 全部线程,因此不会有结果在线程仍在写时被读走。
接口
apsis-math:并行原语
apsis_math::parallel 提供两个入口,是所有并行接口的基础:
| 函数 | 用途 |
|---|---|
thread_count() |
机器的并行度 |
threads_for(len) |
该长度下值得启用的线程数 |
for_each_index(len, f) |
对每个下标调用 f |
map_index(len, f) |
每个下标产出一个值,按下标序返回 |
两个入口都只要求闭包可同步调用(Fn + Sync),因为它们把输入当作共享
的、把输出写进各自负责的槽位;调用方不需要自己同步。
threads_for 在长度小于每线程一千项时返回 1:在这个量级上,启动线程的成本
高于它能省下的工作。
各层的批处理接口
| crate | 接口 | 适用规模 |
|---|---|---|
apsis-sgp4 |
propagate_minutes_at_parallel |
长轨道(≥ 数万样本) |
apsis-sgp4 |
propagate_at_parallel |
整壳一次性传播 |
apsis-access |
find_all_parallel |
数百条轨道 |
apsis-isl |
visibility_matrix_parallel |
数百颗以上(见下) |
每个接口都有一个同名的顺序版本,两者结果逐元素相同、顺序相同,调用方可自由 切换。
判定标准
并非所有批处理都值得并行化。判定依据是单次工作成本与总量:
- 值得并行:单次工作昂贵(≥ 微秒),且逐元素独立,规模可达数百次以上。 典型是 SGP4 传播(约 230 ns/样本,百万样本量级)与可见性搜索(约 7 μs/轨)。
- 不值得并行:
Constellation::instantiate:纯算术,几百颗星只需微秒,线程开销完全淹没。- 调度器:贪心放置本质串行,每次放置影响后续,不是独立循环。
- 事件引擎:单队列时序,无法分块。
- 大地与坐标变换:单点调用本身已是 O(1),没有批量。
mutual_visibility单次:约 4 ns,单次不值得,但成矩阵(见下)。
实测(16 核,release)
SGP4 单条轨道(propagate_minutes_at_parallel)
| 轨道长度 | 顺序 | 并行 | 加速 |
|---|---|---|---|
| 1 天(1,440 样本) | 0.3 ms | 0.3 ms | 1.28× |
| 7 天(10,080) | 2.3 ms | 0.9 ms | 2.46× |
| 30 天(43,200) | 10.1 ms | 1.9 ms | 5.45× |
| 365 天(525,600) | 144.1 ms | 26.0 ms | 5.54× |
结论:轨道越长加速越高,30 天以上稳定在 5.5×。一天以内收益很小——
1,440 个样本分给多线程后每线程不足一千项,低于 threads_for 的阈值。
实践要点:有大量短轨道时,应使用 propagate_at_parallel(整壳一次调用),
而不是对每颗星各调一次并行版——后者会让每颗星都付一次线程启动成本。
可见性矩阵(visibility_matrix_parallel)
| 星数 | 对数 | 顺序 | 并行 | 加速 |
|---|---|---|---|---|
| 200 | 4 万 | 0.16 ms | 0.31 ms | 0.53× |
| 600 | 36 万 | 1.50 ms | 1.37 ms | 1.09× |
| 1,000 | 100 万 | 4.09 ms | 2.50 ms | 1.64× |
结论:单次可见性判定只有几纳秒,小规模下并行反而更慢(线程开销占比高), 数百颗星以上才开始获益,且远未饱和。这个接口是为大规模壳准备的;小壳应直接用 顺序版。接口文档也如实说明了这一点。
跨层组合
bench_parallel 的测量显示,整壳在多核上传播与构建拓扑的并行效果最好,因为
它把整个工作量一次性摊给所有线程。相关数据见该示例的输出。
确定性
并行不改变结果:所有批量接口都逐元素比对顺序版的结果(SGP4 的状态、可见性 的布尔矩阵、access 的过站摘要),顺序也一致。传播本身是确定性的,只依赖时刻, 与如何分块无关;可见性与过站搜索是逐元素独立的。因此同一输入在任意线程数下 产生相同输出,测试也按此断言。