From 2acc2170ad26264e89b354b70c569aa7798fea2e Mon Sep 17 00:00:00 2001 From: ApsisRS contributors Date: Wed, 30 Sep 2026 18:58:02 +0800 Subject: [PATCH] docs: record the scheduler search optimisation --- docs/design/parallel.md | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/docs/design/parallel.md b/docs/design/parallel.md index 3351937..e860b02 100644 --- a/docs/design/parallel.md +++ b/docs/design/parallel.md @@ -51,7 +51,8 @@ 典型是 SGP4 传播(约 230 ns/样本,百万样本量级)与可见性搜索(约 7 μs/轨)。 - **不值得并行**: - `Constellation::instantiate`:纯算术,几百颗星只需微秒,线程开销完全淹没。 - - 调度器:贪心放置本质串行,每次放置影响后续,不是独立循环。 + - 调度器:贪心放置本质串行,每次放置改变后续任务的可行区间,不是独立 + 循环,因此没有并行接口;但其中的搜索已改为单次扫描(见下)。 - 事件引擎:单队列时序,无法分块。 - 大地与坐标变换:单点调用本身已是 O(1),没有批量。 - `mutual_visibility` 单次:约 4 ns,**单次**不值得,但成矩阵(见下)。 @@ -96,3 +97,25 @@ 的布尔矩阵、access 的过站摘要),顺序也一致。传播本身是确定性的,只依赖时刻, 与如何分块无关;可见性与过站搜索是逐元素独立的。因此同一输入在任意线程数下 产生相同输出,测试也按此断言。 + +## 调度器搜索的优化 + +调度器没有并行接口,但它的最坏情况曾达到每任务数百微秒。优化分两步,两者都 +保持结果逐位不变。 + +**第一步:一次扫描代替逐候选测试。** 旧的做法列出所有"可行性可能变化"的时刻, +逐个测试,每次都重新计算每个资源的负载曲线。负载曲线与候选时刻无关,因此改为 +扫一次:把"资源没有余量的区间"从可用窗口中减去,多资源求交,取第一个存活区间 +的起点。结果仍由 `feasible_at` 确认,枚举法保留为浮点边界不一致时的回退。 + +**第二步:确认调用复用索引。** 去掉确认调用后耗时降到八分之一,这定位了真正 +的开销:确认用的公开可行性测试在收集边界时扫描一次任务表,又在每个边界上对每 +个覆盖该边界的放置再扫描一次任务表。把第一步建好的索引传进去,两处扫描都变成 +按标识符直接读取。 + +任务标识符是小而稠密的整数,因此索引用向量而非哈希表:数组下标比哈希一个整数 +更便宜,这在本仓库已测到两次(拓扑的邻接表用索引、这里的任务表用向量)。 + +**结果**:全部任务争用单一资源、容量为瓶颈时,3200 个任务从 6.7 秒降到 0.48 +秒(14 倍),6400 个任务 2.2 秒。计划结果不变——测试在两种资源、窗口不相交的 +场景下逐个比对了每个放置的起止时刻。