如何在Scipy minimizer中并行化目标函数的局部代码而非整体?
解决Scipy优化器中并行化函数内部循环的问题
问题根源
你遇到的「原脚本从头执行」问题,本质是多进程启动时的脚本重复执行:在Windows系统(或部分多进程实现环境中),子进程会重新导入主脚本,若你的优化代码未包裹在if __name__ == '__main__':块中,就会导致整个脚本逻辑被重复触发。
正确实现方法
1. 用ProcessPoolExecutor并行化内部循环
首先将调用优化器的主逻辑放入__main__块,避免子进程重复执行优化流程,同时修正F_1中并行调用F_2的参数传递问题:
from scipy.optimize import minimize import concurrent.futures from lammps import lammps def F_2(X, i): # 执行前置处理逻辑 lmp = lammps() lmp.file("my_other_script_address") # 示例:从LAMMPS提取计算结果 return lmp.extract_variable("target_result", "global", 0) def F_1(X_1, a_1, b_1): total_result = 0 # 初始化进程池并行执行F_2 with concurrent.futures.ProcessPoolExecutor() as executor: # 传递X_1和i参数,生成所有任务 futures = [executor.submit(F_2, X_1, i) for i in range(a_1, b_1)] # 逐个收集子进程的执行结果 for future in concurrent.futures.as_completed(futures): total_result += future.result() return total_result # 主逻辑必须放在此块内,防止子进程重复执行优化流程 if __name__ == '__main__': X_1_initial = [1.0, 2.0] # 优化参数初始值 Arguments = (0, 10) # 循环范围a_1到b_1 Minimized = minimize(F_1, X_1_initial, args=Arguments, method='Nelder-Mead') print(Minimized)
2. 替代方案:用multiprocessing.Pool实现并行
若更习惯使用multiprocessing模块,可采用如下写法:
from scipy.optimize import minimize from multiprocessing import Pool from lammps import lammps def F_2(args): # 打包参数传递,适配Pool.map的接口要求 X, i = args lmp = lammps() lmp.file("my_other_script_address") return lmp.extract_variable("target_result", "global", 0) def F_1(X_1, a_1, b_1): # 构建所有待执行任务的参数列表 args_list = [(X_1, i) for i in range(a_1, b_1)] with Pool() as pool: results = pool.map(F_2, args_list) return sum(results) if __name__ == '__main__': X_1_initial = [1.0, 2.0] Arguments = (0, 10) Minimized = minimize(F_1, X_1_initial, args=Arguments, method='Nelder-Mead') print(Minimized)
关键注意事项
- 参数序列化:确保传递给子进程的参数可被pickle序列化,LAMMPS实例不能跨进程共享,必须在每个子进程内部独立创建。
- 进程数限制:可通过
ProcessPoolExecutor(max_workers=N)或Pool(N)指定进程数,建议设置为CPU核心数的1-2倍,避免资源耗尽。 - 结果完整性:必须等待所有子进程的
F_2执行完成并收集结果后,才能返回给优化器,否则优化器无法获取正确的目标函数值。
内容的提问来源于stack exchange,提问作者Amir Ghorbani
相关产品推荐
相关产品推荐

