PuLP求解路径优化耗时过长,如何实现多线程/多进程及提升效率?
问题
我用PuLP求解路径优化问题,跑一次要1小时,而且只用到1个处理器。想问下能不能搞多线程/多进程?或者有别的提速办法?
多线程/多进程怎么弄?
PuLP本身不负责多进程调度,但你用的CBC求解器天生支持多线程。调用求解器时加个threads参数指定核心数就行:
solver = pl.getSolver('PULP_CBC_CMD', threads=4) # 比如开4线程
这样CBC会自动用上多个处理器核心,速度能提不少。
其他提速技巧
1. 给模型“瘦身”
- 砍冗余变量:你现在的
x_vars是三维组合(i,j,k),如果job和truck数量多,变量会爆炸。提前过滤掉不可能的路线(比如i和j是同一个任务,或者卡车k根本跑不了i→j的路线),生成变量时直接排除,别让这些没用的变量进模型。 - 合并约束:比如第二个约束的嵌套循环,看看能不能用更简洁的方式定义,减少约束的数量——毕竟约束越多,求解器算起来越慢。
2. 调优求解器参数
CBC有一堆参数能调,比如:
- 设
gap值:如果能接受次优解,比如gap=0.05,意思是找到和最优解差距5%以内的解就停,不用死磕最优解。 - 设
maxSeconds:强制限制求解时间,到点就返回当前最好的解。 - 确认
presolve开启(默认是开的),它会自动简化模型,减少计算量。
示例代码:
solver = pl.getSolver('PULP_CBC_CMD', threads=4, gap=0.05, maxSeconds=3600)
3. 优化数据结构
你用i+'-'+j+'-'+k当travel_cost的键,每次访问都要拼接字符串,挺费时间的。改成元组键travel_cost[(i,j,k)],查找速度快多了,代码也更干净。
4. 换个求解器试试
如果CBC还是不够快,能搞到商业求解器(比如Gurobi、CPLEX)的话可以试试——它们的并行优化能力更强,处理大规模模型更高效。不想花钱的话,开源的SCIP求解器也不错,PuLP也能调用它。
整理后的代码参考
变量与目标函数
# 决策变量X:过滤i=j的冗余路线 x_vars = LpVariable.dicts( "route", [(i,j,k) for i in job_id for j in job_id for k in truck_id if i != j], lowBound=0, upBound=1, cat=LpBinary ) # 决策变量Y y_vars = LpVariable.dicts( "work", [(j,k) for j in job_id for k in truck_id], lowBound=0, upBound=1, cat=LpBinary ) # 目标函数:用元组键访问travel_cost opt_model += lpSum( x_vars[(i,j,k)] * travel_cost[(i,j,k)] for i in job_id for j in job_id for k in truck_id if (i,j,k) in x_vars )
约束条件
# 约束:排除卡车k无法访问的yard对应的路线 for k in truck_id: opt_model += lpSum( x_vars[(i,j,k)] for j in job_id for i in yard_id if i != truck_yard[k] ) == 0 # 约束:任务j被卡车k承接的次数等于y_vars[j,k] for j in job_id: for k in truck_id: # 只取存在的x变量,避免KeyError relevant_x = [x_vars[(i,j,k)] for i in job_id if (i,j,k) in x_vars] opt_model += lpSum(relevant_x) == y_vars[(j,k)]
求解器(开启多线程)
solver = pl.getSolver('PULP_CBC_CMD', threads=4, gap=0.05) results = opt_model.solve(solver)
内容的提问来源于stack exchange,提问作者petch
相关产品推荐
相关产品推荐

