34 lines
2.6 KiB
Markdown
34 lines
2.6 KiB
Markdown
# 画线绘制候选集去重 O(n²) → O(n)
|
||
## 修复提交
|
||
|
||
| 仓库 | 分支 | Commit ID | 说明 |
|
||
| --- | --- | --- | --- |
|
||
| `hmdrawlinebasicsdk` | `work-clz-fuhm-1979-drawline-dedup` | `c3f8e6bc2ca44af9afa9bf0163d88d2508d55a0a` | 画线绘制候选集去重 O(n²)→O(n) |
|
||
| `harmony-ths-futures` | `work-20260818-clz-FUHM-1979-apm-appfreeze` | `ce0719178530b5ca64272c6c1e90b5bcdb8297fc` | 接入 `libs/drawlinebasic-1.2.1-dedup-opt.har` 及主工程 overrides |
|
||
|
||
## 问题
|
||
|
||
冻屏聚类 20020217(5 次)、20020340(3 次):主线程栈停在 `DrawingApiImpl.appendUniqueLines → findIndex → isSameLine`。`drawLines()` 每帧渲染都会调用 `getLinesToDraw()` 重建绘制候选集,其中 `appendUniqueLines` 用 `source.forEach` 嵌套 `target.findIndex` 判重,复杂度 O(n·m)。画线数量较多或跨周期线合并时,主线程持续繁忙触发 3S/6S 冻屏上报。
|
||
|
||
判重语义(原 `isSameLine`):同对象引用、本地 ID 或远端 ID 任一非空且相等即判为同一条线。注意本地 ID 不同但远端 ID 相同的两条线也判同一条,因此不能用单一 key 去重。
|
||
|
||
## 优化方案
|
||
|
||
1. `appendUniqueLines` 改为三个 Set(对象引用 `refSet`、本地 ID `localIdSet`、远端 ID `lineIdSet`)一次遍历完成判重,复杂度降为 O(n);判重语义与原 `isSameLine` 逐条等价,目标列表插入顺序不变;原私有方法 `isSameLine` 随之删除。
|
||
|
||
## 影响范围
|
||
|
||
- 仅画线绘制候选集的去重实现;画线数据模型、持久化、云端合并、绘制样式与命中逻辑不变。
|
||
- 每帧绘制候选集重建仍会分配三个 Set,列表本身不缓存;进一步可考虑按 cache 版本缓存合并结果(本次未做)。
|
||
|
||
## 预期收益与边界
|
||
|
||
候选集去重由 O(n·m) 降为 O(n),画线数量越大收益越明显,直接消除该冻屏聚类的热点函数。判重语义与原实现逐条等价(含"本地 ID 不同但远端 ID 相同判同一条"的边界情形),重复描边、线条层级行为不变。画线 SDK 侧彻底根治仍建议上游将 `getLinesToDraw` 的合并结果按缓存版本缓存,避免每帧重建。
|
||
|
||
## 验证建议
|
||
|
||
1. 执行 `./claude_tool/claude_compile.sh` 编译通过。
|
||
2. 真机在画线较多(数十条以上)的 K 线页面滑动、切换周期,确认绘制行为与改动前一致,冻屏主线程栈不再出现 `appendUniqueLines → findIndex`。
|
||
3. 回归跨周期画线:新建、云端合并、编辑态切换、删除场景下无重复描边,线条层级与命中结果不变。
|
||
4. 检查最终产物中 `@b2c-f/drawlinebasic` 仅存在一份(overrides 生效)。
|