使用Pathos调用对象方法实现多进程无性能提升求助
问题描述
我需要调用多个world对象的buildWorld方法,这是计算密集型的耗时任务,根据world的设置不同有时会耗时数小时。最初遇到pickle无法序列化对象方法的问题,参考资料后尝试用pathos实现多进程,但未获得性能提升。排查后排除了序列化耗时的问题,随后改为在子进程内创建world对象并保存为文件以避免序列化操作,还尝试了三种方案:Pathos ProcessingPool、multiprocess的Process对象、ThreadPool,但多进程运行耗时与单进程一致,需要技术指导。
尝试的三种实现代码
方法1(Pathos ProcessingPool):
import pathos.multiprocessing as mp def run_world_building(worldNum): myWorld = emptyWorld(worldNum) # 开销极低 myWorld.buildWorld() # 开销极大 myWorld.save() # 将世界信息保存为文件 p = mp.ProcessingPool(3) p.map(run_world_building, range(0,3))
方法2(multiprocess的Process对象):
import multiprocess as mp def run_world_building(worldNum): myWorld = emptyWorld(worldNum) # 开销极低 myWorld.buildWorld() # 开销极大 myWorld.save() # 将世界信息保存为文件 processes = [] for i in range(0,3): p = mp.Process(target=run_world_building, args=(i,)) processes.append(p) # 我分开了启动和等待的循环,但不确定是否有必要 for i in range(0, 3): processes[i].start() for i in range(0,3): processes[i].join()
方法3(使用ThreadPool):
from pathos.pools import ThreadPool def run_world_building(worldNum): myWorld = emptyWorld(worldNum) # 开销极低 myWorld.buildWorld() # 开销极大 myWorld.save() # 将世界信息保存为文件 p = ThreadPool(3) p.map(run_world_building, range(0,3))
核心排查方向
ThreadPool方案本质缺陷
ThreadPool基于线程实现,Python的GIL锁会限制计算密集型任务的多线程并行能力,多线程会退化为串行执行,所以该方案性能和单进程一致是正常现象,直接放弃即可。多进程未真正并行
- 检查机器CPU核心数是否≥3,若核心数不足,多进程会出现调度竞争,无法发挥并行优势。
- 运行任务时打开系统监控(Windows任务管理器、Linux top),查看CPU使用率是否拉满。若仅单个核心满载,说明多进程未真正并行执行。
buildWorld内部的串行瓶颈- 检查方法内是否使用全局锁、共享资源(全局变量、单例资源、同一文件写入),这类资源会导致多进程互相等待,抵消并行效果。
- 检查是否调用了单线程第三方库(如部分科学计算库默认单线程),这类库会强制任务串行执行。
第三方库兼容性问题
multiprocess是第三方库,存在潜在兼容性bug,建议替换为Python标准库multiprocessing测试。
解决方案建议
1. 改用标准库multiprocessing实现多进程
替换方法2为标准库版本,同时添加if __name__ == "__main__":(Windows系统强制要求,也能避免Unix系统潜在问题):
import multiprocessing as mp def run_world_building(worldNum): myWorld = emptyWorld(worldNum) # 开销极低 myWorld.buildWorld() # 开销极大 myWorld.save() # 将世界信息保存为文件 if __name__ == "__main__": processes = [] for i in range(3): p = mp.Process(target=run_world_building, args=(i,)) processes.append(p) p.start() for p in processes: p.join()
2. 排查并修复buildWorld内部瓶颈
- 若调用了单线程第三方库,配置库启用多线程/多进程(如NumPy设置
MKL_NUM_THREADS、PyTorch指定多GPU)。 - 确保
myWorld.save()写入独立文件路径,避免多个进程争夺文件锁导致串行。
3. 进程池优化(标准库版本)
使用标准库multiprocessing.Pool,并设置maxtasksperchild避免内存泄漏:
import multiprocessing as mp def run_world_building(worldNum): myWorld = emptyWorld(worldNum) myWorld.buildWorld() myWorld.save() if __name__ == "__main__": with mp.Pool(processes=3, maxtasksperchild=1) as pool: pool.map(run_world_building, range(3))
4. 验证并行状态
在任务中添加计时打印,确认多进程是否真正并行:
import time def run_world_building(worldNum): start_time = time.time() print(f"进程 {worldNum} 启动于 {time.strftime('%Y-%m-%d %H:%M:%S')}") myWorld = emptyWorld(worldNum) myWorld.buildWorld() myWorld.save() end_time = time.time() print(f"进程 {worldNum} 完成,耗时 {end_time - start_time:.2f} 秒")
若各进程启动时间接近,说明并行正常;若依次启动,需进一步排查内部串行瓶颈。
内容的提问来源于stack exchange,提问作者Pran

