PDF 解析

批量解析 PDF 时,为什么每个进程应自己打开文件

多进程任务应传入可序列化参数,由各工作单元独立打开文档,而不是共享 Document 或 Page 对象。下面测试分段覆盖和独立打开的工作函数;为保持可移植与可审计,示例串行调用,不将它冒充多进程性能测试。

阅读文本 / Reading text
本文使用合成样本演示处理方法。代码已通过隔离环境中的示例检查;这不代表对所有真实文件或产品效果的保证。处理重要文件前,请保留原件,并按文中的边界与验收项复核。 这篇先解决哪一个问题 多进程任务应传入可序列化参数,由各工作单元独立打开文档,而不是共享 Document 或 Page 对象。下面测试分段覆盖和独立打开的工作函数;为保持可移植与可审计,示例串行调用,不将它冒充多进程性能测试。 自包含的合成示例 依赖见导入列表。代码在内存中构造输入;运行记录单独提供,不代表对所有真实文件的保证。 import pymupdf def partition(total, chunk): if type(chunk) is not int or chunk <= 0: raise ValueError("positive chunk required") return [(start, min(start + chunk, total)) for start in range(0, total, chunk)] def worker(raw, start, end): with pymupdf.open(stream=raw, filetype="pdf") as doc: return [(i, doc[i].get_text()) for i in range(start, end)] with pymupdf.open() as doc: for index in range(5): doc.new_page().insert_text((50, 50), f"Page {index}") raw = doc.tobytes() tasks = partition(5, 2) assert tasks == [(0, 2), (2, 4), (4, 5)] results = [item for start, end in tasks for item in worker(raw, start, end)] assert [i for i, text in results] == list(range(5)) assert all(f"Page {i}" in text for i, text in results) assert partition(0, 2) == [] 为什么不能把 Document 对象传给子进程 根本原因在于 Document 内部持有指向底层 C 结构的指针和文件句柄。这些资源绑定于创建它的进程内存空间,跨进程传递后指针失效,句柄也无法被另一个进程合法访问。正确的做法是只传递文件名(字符串)和页码范围等可序列化参数,让每个子进程在自己的内存空间中独立调用 pymupdf.open() 。这并非性能缺陷,因为子进程作为独立实体,无论如何都需要自己的文档实例来安全执行提取或渲染操作。 合成示例:正确的输入与危险的边界 正确输入 :传递元组 (segment_id, filename, start_page, end_page) 。其中 filename 是字符串路径, start_page 与 end_page 是整数。子进程收到后自行打开文件,处理指定页码区间,返回结果列表。 错误/边界输入 :若传入的页码范围为 (18, 25) ,而文档实际只有 20 页,子进程在访问第 21 页时将触发索引越界。另一种常见错误是直接传递 Document 对象,这会因 pickle 失败而中断。还有一种隐蔽情况:多个子进程同时向同一个输出文件写入结果,由于缺乏同步机制,会导致内容交错或损坏。 处理方式是在子进程入口处立即校验页码范围是否超出 doc.page_count ,并对所有 I/O 操作使用独立的目标路径或内存缓冲。对于不可序列化的对象,应在设计阶段就排除其出现在任务参数中,而非依赖运行时捕获异常。 完整 Python 示例与依赖说明 注意: pool.map 的 chunksize 参数在此使用默认值 1,适用于任务粒度较大的场景。若页码极多且单页处理极快,可增大 chunksize 减少 IPC 开销,但本示例聚焦安全性而非调优。 验收标准与人工审查边界 观察现象 可能原因 处理决定 pickle.PicklingError 或子进程静默崩溃 传递了 Document/Page 等不可序列化对象 仅传递字符串、整数、元组等基本类型 部分页码返回空字符串 页码范围超出实际页数,或页面为纯图像无文本层 校验页码边界;对纯图页面标记需 OCR(属预期行为) 输出文件内容错乱 多进程写入同一文件 每进程写独立临时文件,主进程合并 内存占用随进程数线性增长 每个进程加载完整文档 接受此开销;若文档过大,改用分页流式处理 此模式不适用于需要跨页上下文关联的任务(如表格跨页合并、全文索引构建),因为各进程彼此隔离。遇到此类需求,应退回单进程处理或设计专门的分块聚合策略。此外,代码演示仅验证了“能安全并行提取”,不等于端到端效果可用——文本质量、编码正确性、格式保留程度仍需人工抽样审查。特别是扫描版 PDF,纯文本提取可能完全失效,此时必须引入 OCR 环节。 参考与下一步 将这份检查清单用于文档翻译 先把页面顺序、来源位置与文本完整性检查清楚,再把同一份脱敏样本交给翻译流程。译后仍要检查标题、正文和图注是否正确对应,不能只看文字是否通顺。 OmniDoc(产品入口) 提供多格式文档翻译入口,官网介绍了 OCR、术语表与双语对照功能。对希望直接从文件开始处理的团队,这是一条值得用实际样本评估的路径。请使用有权上传的脱敏文件,并用本篇的检查项复核结果;这里不声称 OmniDoc 使用了本文的开源库或内部算法,也不以示例代替产品性能测试。 原厂接口依据: PyMuPDF 文档 。 - 1 -
更新于 2026-10-08