Memento多进程架构解析:如何兼顾实时录制与OCR处理的性能平衡
【免费下载链接】MementoMemento is a Python app that records everything you do on your computer and lets you go back in time, search, and chat with a LLM (Large Language Model) to find back information about what you did.项目地址: https://gitcode.com/gh_mirrors/mem/Memento
Memento 是一款开源的 Python 桌面记录应用,它每隔 2 秒自动截屏一次,把你在电脑上的所有操作变成一段可以回放、全文搜索、甚至能与大模型对话的"记忆时间线"。要在不卡顿的前提下同时完成实时录制、OCR 文字识别、数据库索引三件重活,Memento 选择了一套教科书式的多进程架构:主进程负责录制与调度,独立工作进程负责最耗时的 OCR 识别,再用两条队列实现协作。本文带你拆解这套设计的每一个关键节点,看看它是如何在实时录制与 OCR 处理之间找到性能平衡的。
为什么单进程扛不住?先看清工作负载 🧱
在理解架构之前,先看看 Memento 每秒钟要完成哪些任务:
| 任务 | 频率 | 成本 |
|---|---|---|
| 屏幕截图 | 每 2 秒一帧(1920x1080) | 低 |
| H.264 视频编码 | 每帧实时写入 | 中 |
| OCR 文字识别 | 每帧逐行提取文本 | 高 |
| 文本写入 SQLite + 向量库 | 每帧一次 | 中 |
| 应用分段与内容合并 | 持续进行 | 低 |
其中OCR 是最重的瓶颈:一张 1080p 截图上可能有好几十行文字,逐行调用 Tesseract 引擎需要数百毫秒甚至更久。如果录制和 OCR 串行执行,主循环会被 OCR 拖住,导致截屏节奏紊乱、视频时间轴失真——这正是"实时性"的致命伤。
所以 Memento 的思路很直接:把最重的活拆出去单独干。
Memento 整体架构:一条"流水线"上的三个角色 🏭
Memento 的后台核心在 memento/background.py 中,它构建了一个典型的生产者—消费者模型:
主进程(Producer) 工作进程(Consumer) ┌──────────────┐ ┌──────────────┐ │ 截屏 + 视频编码 │ ──put──▶│ 帧差异检测 │ │ 元数据写入 │ images_queue │ OCR 文字识别 │ │ 结果入库 │ ◀─get─── │ │ └──────────────┘ results_queue └──────────────┘- 主进程(生产者):负责截屏、H.264 编码、写元数据,并把每一帧丢进
images_queue; - OCR 工作进程(消费者):从队列中取帧,做文字识别后把结果放回
results_queue; - 两条
multiprocessing.Queue队列:充当进程间通信的"传送带",让双方互不阻塞。
这样主进程永远不用等 OCR 结束,录制节奏稳如钟表;OCR 进程则像流水线上的工人,专注于一件事,效率更高。
主进程:一边实时录制,一边当"总调度" 🎥
主进程的职责集中在Background.run()方法中,它每轮循环做四件事:
- 截屏并编码:用
mss抓取屏幕,交给 utils.py 中的Recorder类编码为 H.264 视频片段,保证 2 秒一帧的恒定节奏; - 投递识别任务:把当前帧、上一帧、窗口标题等打包放入
images_queue,让 OCR 进程异步处理; - 写入元数据:先把"窗口标题 + 时间"快速写入 JSON 元数据缓存,等 OCR 结果回来后补上文字和坐标;
- 收取结果入库:从
results_queue非阻塞地取回识别结果,写入 db.py 中的 SQLite 数据库,并同步到 Chroma 向量库供语义检索。
主进程在截屏间隙用asyncio.run(self.rec.new_im(im))异步编码视频帧,把"等编码"的时间也省了下来,这就是实时录制不掉帧的秘密。
OCR 工作进程:聪明的"偷懒"才是性能关键 🧠
工作进程的逻辑在process_images()中,看似是无限循环取帧,实则藏着两个精妙的性能优化:
优化一:帧差异检测,跳过"静止画面"
diffscore = utils.imgdiff(im, prev_im) if diffscore < 0.1: # 画面几乎没变,跳过 OCR如果当前帧和上一帧的差异度低于阈值(0.1),说明屏幕内容没变化,识别结果必然一样,直接跳过——这能省下大量无意义的 OCR 计算。你正在阅读长文档、看视频时,绝大多数帧都会被快速过滤。
优化二:跳过时间线窗口
elif window_title == "memento-timeline": # 用户正在看时间线,无需记录当检测到用户正停留在 Memento 自己的时间线界面时,同样跳过识别,避免"自拍自己"的无效劳动。
为什么只开 1 个 Worker?
代码中nb_workers = 1,注释里写得很直白:目前一个 worker 性能就够用了。因为帧差异检测已经过滤掉了大部分重复帧,实际需要 OCR 的帧并不多,一个 Tesseract 实例足以消化,反而避免了多进程抢占 CPU 和内存的额外开销。
双队列通信:进程间协作的"传送带" 🚚
Memento 使用multiprocessing.Queue作为进程间通信(IPC)的桥梁:
images_queue:主进程投递待识别帧(数据量小,只传关键信息,避免复制大图带来的开销);results_queue:OCR 进程回传识别结果(文字、坐标框、置信度)。
主进程消费结果时采用非阻塞读取(get(False)),一次循环把队列里已有的结果全部取完,取不到就继续下一轮录制——这样即使 OCR 偶发延迟,主进程也绝不会停下等待,实时录制与 OCR 处理天然解耦。
性能平衡的四个关键点总结 ⚖️
| 设计 | 作用 |
|---|---|
| 生产者—消费者双进程模型 | 录制与识别互不阻塞,保证实时性 |
| 帧差异检测(imgdiff 阈值) | 过滤静止帧,大幅降低 OCR 负载 |
| 时间线窗口跳过 | 避免无意义的自我录制 |
| 双队列 + 非阻塞消费 | 进程间高效协作,容忍偶发延迟 |
这四招组合拳,让 Memento 在普通家用电脑上也能"边录边识"而不卡顿。
快速上手体验 ⚡
想亲手感受这套架构,先安装依赖:
pip install -e .然后启动后台录制进程:
memento-bg再开一个终端启动时间线界面:
memento-timeline之后就能滚动时间线回放过去、Ctrl+F全文搜索、Ctrl+T与大模型对话。想深入源码,建议从 memento/background.py 的主循环读起,再对照 memento/OCR.py 和 memento/db.py 理解数据流转。
结语 🎯
Memento 的多进程架构给所有"录制 + 分析"类应用提供了一个优秀范本:实时任务与重计算任务分离,用队列解耦,用智能过滤减少无效计算。当你在时间线上轻松找回一个月前看过的内容时,别忘了背后这套精妙的设计——它用最少的资源,换来了最流畅的体验。
【免费下载链接】MementoMemento is a Python app that records everything you do on your computer and lets you go back in time, search, and chat with a LLM (Large Language Model) to find back information about what you did.项目地址: https://gitcode.com/gh_mirrors/mem/Memento
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考