如何预定义Gurobi模型实现迭代阶段多场景多进程并行求解
解决方案
首先明确:Gurobi的Model和Env对象属于C扩展实现的非序列化对象,无法直接通过multiprocessing的默认序列化机制传递给子进程,因此无法直接在主进程定义一次后直接分给多个子进程使用,但可以通过以下低成本方案实现「仅构建一次基础模型」的需求,避免每轮迭代/每个子进程重复定义模型逻辑:
方案1:基础模型预导出为MPS/LP文件(推荐,跨平台兼容)
这是最稳定高效的实现方式:
- 主进程启动后先一次性构建好基础模型,导出为本地MPS格式文件(MPS是Gurobi支持的标准模型格式,读写速度极快)
- 所有子进程求解场景时,直接读取该基础模型文件,再修改对应约束即可,无需重复编写模型构建逻辑
- 基础模型文件仅需生成一次,后续所有迭代轮次都可以复用
示例代码
import multiprocessing as mp import gurobipy as gp import os # 全局配置:基础模型路径,仅生成一次 BASE_MODEL_PATH = "base_model.mps" def build_base_model(): """主进程调用:一次性构建基础模型并导出""" with gp.Env() as env, gp.Model(env=env) as base_model: # 这里写你的基础模型定义逻辑,所有场景通用的部分都在这里实现 # ...... # 导出基础模型 base_model.write(BASE_MODEL_PATH) def solve_scene(input_data): """子进程调用:读取基础模型+修改约束+求解""" scene_id, constraint_params = input_data with gp.Env() as env, gp.read(BASE_MODEL_PATH, env=env) as model: # 根据当前场景参数调整对应约束,比如修改RHS、增减约束等 # 示例:调整指定约束的右侧值 # model.getConstrByName(f"constr_{scene_id}").RHS = constraint_params model.optimize() # 提取求解结果返回 res = { "scene_id": scene_id, "obj_val": model.ObjVal if model.status == gp.GRB.OPTIMAL else None # 其他需要的结果字段 } return res if __name__ == '__main__': # 第一步:仅启动时运行一次,构建并导出基础模型 if not os.path.exists(BASE_MODEL_PATH): build_base_model() # 迭代流程示例 for iter_num in range(10): # 你的迭代轮次 print(f"开始第{iter_num}轮迭代") # 组装当前轮次的9个场景输入参数 scene_inputs = [(i, f"param_{i}") for i in range(9)] # 多进程并行求解 with mp.Pool(processes=9) as pool: iter_results = pool.map(solve_scene, scene_inputs) # 处理当前轮次的求解结果 # ......
方案2:使用Gurobi原生多场景特性
如果你的9个场景仅涉及约束右端值、变量上下界、目标系数的调整,可以直接使用Gurobi内置的Multi-Scenario功能,无需自己实现多进程逻辑,Gurobi会自动并行求解所有场景,代码实现更简洁:
import gurobipy as gp with gp.Env() as env, gp.Model(env=env) as model: # 构建基础模型 # ...... # 设置场景数为9 model.NumScenarios = 9 for scene_id in range(9): model.params.ScenarioNumber = scene_id # 给当前场景设置对应约束/变量参数 # model.getConstrByName("xxx").ScenNRHS = xxx # 一次性并行求解所有场景 model.optimize() # 逐个读取场景结果 for scene_id in range(9): model.params.ScenarioNumber = scene_id print(f"场景{scene_id}目标值:{model.ObjVal}")
注意事项
- 禁止多个进程共用同一个Gurobi
Env或Model实例,会引发内存错误、许可冲突等异常 - 若使用Linux/macOS系统的fork模式多进程,理论上可以继承主进程的模型对象,但容易出现Gurobi内部状态冲突问题,稳定性远低于预导出MPS的方案,不推荐使用
内容的提问来源于stack exchange,提问作者Sanjeev
相关产品推荐
相关产品推荐

