Python多进程通过fork共享只读对象运行失效问题求助
背景说明
关于多进程共享内存的主题已有大量公开讨论,我也查阅了多份技术资料寻求解决方案。
我尝试通过Python multiprocessing模块优化代码性能,直接使用pool.apply_async运行核心计算仅带来约50%的性能提升,无法满足需求。性能分析显示进程fork环节存在大量开销。
我原本设计了「任务队列+固定数量工作进程(每CPU核对应1个)+结果队列」的实现方案,预期性能会更优,但实际测试性能略低于apply_async方案,该场景下的开销主要来自队列的put和get操作,涉及的数据体量中等。
考虑到我的业务数据是静态只读的,fork后不会对数据做写入操作,因此我打算把原本通过管道/队列传输的数据设置为全局变量,已查阅的相关技术资料也支持该实现思路。
我先写了简单示例做验证,运行效果符合预期,小体量测试性能提升明显,示例使用的mp.pool大小为CPU核数减1。
示例伪代码如下:
serve: 共N个serve进程,轮询job-que直到获取工作项字典,传递给worker执行。 worker: 接收工作项完成计算,将结果推入result-que。
除此之外还有记录工作量的簿记逻辑。
遇到的问题
将验证后的代码应用到实际业务场景时运行失败,fork子进程上下文中的部分全局数据失效。其中args_dict可以正常访问,但另外的一个列表、一个字典、一个类对象要么为空要么数据无效,而这些数据类型在之前的简单示例中都可以正常运行。我打印了四个对象的内存id,仅args_dict的id值和主进程中一致。
可以确定这些全局对象在子进程没有执行任何读写操作前就已经失效:我的PManager类在数据通过队列传输、以及对象设为全局的场景下都能正常运行,启动worker前代码会赋值并校验全局变量,此时数值都是正确的,但进入实际工作代码时4个全局对象中有3个异常,仅1个正常。测试代码只有2个文件,项目代码虽多但仅涉及3个文件的交互,逻辑上不该出现该问题。
我已经尝试调用gc.freeze()冻结主进程内存,测试结果依然没有改善。
我没有尝试MP.manager方案,因为根据我查阅的相关评论以及对其实现逻辑的理解,该方案不适用于本场景。
恳请各位给出解决方案建议。
内容的提问来源于stack exchange,提问作者eorojas

