# 并行化 本文件记录并行化的判定标准、提供的接口,以及实测结果。跨层的单位与坐标约定见 [单位与坐标约定](units.md),分层边界见 [分层边界](layers.md)。 ## 为什么不引入线程池 工作区禁止任何第三方 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 的过站摘要),顺序也一致。传播本身是确定性的,只依赖时刻, 与如何分块无关;可见性与过站搜索是逐元素独立的。因此同一输入在任意线程数下 产生相同输出,测试也按此断言。