Python用threading/multiprocessing并行运行行星模拟代码速度无提升求助
问题根因
- 你在多线程/多进程的循环代码中,每次启动子任务后立刻调用
join()方法,会阻塞主进程直到当前子任务执行完成,完全没有并行执行的效果,本质还是串行执行所有任务 - Python多线程受GIL(全局解释器锁)限制,对于你这种CPU密集型的数值计算任务,多线程无法利用多核CPU,不会带来性能提升
- 手动单个创建多进程的写法还要承担进程启动的额外开销,所以最终耗时比串行还高
解决方案
使用concurrent.futures.ProcessPoolExecutor进程池工具,自动调度多核CPU运行任务,不需要手动管理进程启停,同时也兼容你用生成器传入参数的低内存需求,示例代码如下:
import time import numpy as np import rebound from concurrent.futures import ProcessPoolExecutor from scipy.stats import rms # 你代码里用到的rms需要对应导入 # 此处粘贴你原来的所有函数定义:planet1_pars、set_grids_fakePlanet、computeTTVs、run_rebound if __name__ == '__main__': peiom_grid = set_grids_fakePlanet(planet1_pars()) start = time.time() # max_workers按你的CPU核心数设置,8核CPU可以设为7~8,留1个核心给系统调度 with ProcessPoolExecutor(max_workers=8) as executor: # 直接把参数生成器传给map方法,自动分配任务到各个进程 results = list(executor.map(run_rebound, peiom_grid)) end = time.time() print((end - start)/60, 'min') # results变量就是所有run_rebound返回的结果集合,可以后续做存储、分析处理
额外优化建议
- 如果你的参数网格特别大,不需要一次性把所有结果存在内存中,可以改用
executor.submit配合as_completed逐个处理返回的结果 - 若你用到的numpy是MKL编译版本,默认会启动多线程运算,和多进程抢占CPU资源,可在运行脚本前设置环境变量
export OMP_NUM_THREADS=1、export MKL_NUM_THREADS=1,限制numpy单线程运行,避免资源竞争降低效率 - 生产环境可以配合
tqdm库添加进度条,方便观测大网格的运行进度
内容的提问来源于stack exchange,提问作者Douglas Rodrigues Alves
相关产品推荐
相关产品推荐

