摘要
战场画面上方有一条行动条:一排小卡片,按顺序显示接下来轮到哪些部队行动。程序要认出每张卡是哪种生物,做法是把卡片和资料库里每种生物的标准图标逐一做“带遮罩的模板匹配”(在 4 个尺度、正反两个镜像方向上比较),按分数给出前三名候选,这一步叫排名(rank)。
测量一张开局截图时发现,热状态下战场读取近 20 秒,其中约 98.7% 花在 13 张卡的逐卡排名上。本实验准备了一个私有候选:把各卡的排名放进 2 个 Python 线程并行执行,结果按原卡序取回,算法、图标库、尺度、阈值都不变。实验设计了严格的冻结与计时协议,第一次正式测量因一个数据库辅助文件的修改时间变化,在发出第一个请求前就按规则停止;协议修正后再测,同一常驻进程的读取从 20.15 秒降到 12.38 秒(1.63 倍,减少 38.6%),完整输出与原方法逐字段一致。这只是一张图的开发诊断,没有接入默认流程。
要回答的问题
在不改变任何识别结果的前提下,把行动条逐卡排名并行化能省多少时间?瓶颈到底在哪一段?
数据与来源
- 唯一的游戏输入:10 月 2 日一段录像第 420 秒附近的一张草地开局截图(实际解码时刻 420.0087 秒),沿用之前一次请求的配置(自动模式、GPU、指定玩家头像)。
- 不使用其他测试图,也不导入参考答案。
方法
私有候选:只有“当前行动卡排名”这一步进入一个单次请求内的 2 线程池,卡片计划不超过 32 张;完成顺序不影响结果顺序;后面的卡先失败也不会覆盖前面卡的结果或异常。图标库冻结为只读,原生图片和模板都是只读视图。请求结束时等待、取消未开始的任务并关闭线程池,没有常驻线程或跨帧缓存。只接受已核查过的 OpenCV 4.10.0 构建,未知版本拒绝启用;不改 OpenCV 的全局线程设置。
冻结:运行前登记约 2,205 条文件元数据(源码、资料库、标准图标、OCR 模型缓存、Python 和依赖版本),任何变化都停止,不静默重新冻结或重跑。
计时协议:同一个新启动的常驻进程,依次执行“冷”请求一次(进程启动后的首次请求,不是硬件冷启动)、“热”请求一次;只有在两者都成功、战场读取成功、至少 2 张卡、热状态下排名占战场读取 ≥50%、冷/热的完整输出(去掉计时字段)严格一致时,才执行一次候选请求。总共最多 3 个请求,不重试、不额外预热、不换图。每一段(初始化、场景发现、路由 OCR、资源加载、各批 OCR、逐卡排名、战场识别、整体调用、进程 CPU)分别计时;各段有嵌套关系,不能相加。
输出比较:只删除三类计时字段,其余身份、数量、颜色、框、前三名顺序、所有分数、尝试记录、未知和错误都严格比较,不允许浮点容差,整数和浮点类型变化也算不一致。
设置
软件准备:新增 23 项测试,连同路由和行动者相关重点测试共 139 项通过;完整 Perception 回归 6,409 项通过、0 失败。测试用合成图标库和随机像素,验证真实的带遮罩 OpenCV 匹配、并列排序、镜像/尺度、只读源、任务乱序完成仍保持输出顺序等。没有构造真实模型。
结果
第一次测量:首请求前停止。 获得独占机器窗口后,冻结检查发现只有一个文件变了:资料库 SQLite 数据库的 -shm 辅助文件(共享内存索引文件,不含数据库内容),大小和 inode 不变,只有修改时间变了。按规则立即停止:真实请求 0 次,没有任何计时或比较。没有重试、放宽检查或删除文件,而是提出一个精确的协议修正:只排除这一个 -shm 文件的元数据变化,数据库本体和 -wal 文件(可能含已提交但未写回的事务)照常检查。
修正协议后的真实测量(3 次请求用满):
| 项目(秒) | 冷 | 同进程热 | 同进程候选 |
|---|---|---|---|
| 整体调用 | 25.6589 | 20.1545 | 12.3779 |
| 战场识别 | 20.5798 | 19.7694 | 11.8812 |
| 进程 CPU | 196.80 | 186.08 | 125.36 |
| 路由 OCR | 4.8176 | 0.3001 | 0.4124 |
| 资料库资源加载 | 0.2054 | ≈0 | ≈0 |
| 13 卡逐卡排名累计 | 19.5750 | 19.5150 | (并行,不走串行计时) |
热状态下逐卡排名占战场读取 98.7127%,满足门槛。候选:计划 13 卡、完成 13、失败 0;两个线程的任务累计 21.84 秒,但外层实际等待只有 11.64 秒,线程池已关闭。冷↔热、热↔候选的完整输出都严格相等。
失败与负结果
- 第一次正式测量因
-shm文件修改时间变化而零请求停止,这个失败和原冻结计划都原样保留。修改时间是谁改的无法确定。 - 并行任务的累计耗时(21.84 秒)略高于串行(19.51 秒),说明并行本身有开销;节省来自外层等待缩短。
局限
- 只有一张图、三次请求,不能报 p95,不能推广到其他场景,也不证明 App 三秒目标或识别精度提升。
- 候选后仍约 12.38 秒,远未达到实时要求。
- “冷”只表示新常驻进程的首个请求,不是操作系统或 GPU 冷启动。
- 候选没有公共导出,App 和命令行都不接入;默认路径、阈值、图标库、尺度都没变。
结论与下一步
瓶颈非常集中:行动条的逐卡模板匹配几乎占满了战场读取时间。两线程并行在不改变任何输出的情况下把这张图的读取缩短了约 39%。是否接入默认流程,需要先在其他已保存场景上做等价回放,并由消费端另行集成和验收;本次测量额度已用完,原证据和失败历史都保留。
Comments