Docplex CP中Callback+Blackbox多Worker触发AssertionError问题求助
解决Docplex CP多Worker下BlackBox回调的AssertionError并提取求解信息
问题根源
多Worker模式下,求解器的多进程事件分发机制会将BlackBox专属事件混入常规回调事件队列,导致Docplex高层回调收到非预期事件,触发AssertionError。
解决方案
1. 自定义回调时显式过滤BlackBox事件
修改回调函数,跳过所有BlackBox相关事件,只处理解更新和间隙计算的核心事件:
from docplex.cp.callback import CpoCallback, CpoCallbackEventType class SolverInfoCallback(CpoCallback): def __init__(self): super().__init__() self.current_best = None self.current_gap = None def invoke(self, solver, event): event_type = event.get_type() # 跳过BlackBox事件,避免断言错误 if event_type.startswith("BLACKBOX"): return # 处理解更新事件 if event_type == CpoCallbackEventType.SOLUTION: sol = solver.get_solution() self.current_best = sol.get_objective_value() print(f"找到新解: {self.current_best}") # 处理间隙更新事件 elif event_type == CpoCallbackEventType.GAP: self.current_gap = solver.get_mip_gap() print(f"当前间隙: {self.current_gap:.2%}")
2. 手动绑定回调到求解器实例
绕过Docplex的默认回调注册逻辑,直接将回调绑定到求解器的指定事件类型,避免多进程事件混淆:
# 假设你已经构建好带BlackBox的模型(以sched_jobshop_blackbox.py为例) model = ... # 你的模型定义 # 创建回调实例 info_cb = SolverInfoCallback() # 获取求解器并绑定回调 solver = model.get_solver() solver.add_callback(info_cb, [CpoCallbackEventType.SOLUTION, CpoCallbackEventType.GAP]) # 启动多Worker求解 solution = solver.solve(workers=4, time_limit=30) # 输出最终结果 print(f"最终最佳目标值: {info_cb.current_best}") print(f"最终间隙: {info_cb.current_gap:.2%}")
3. 可选:禁用BlackBox事件传递
如果不需要BlackBox的事件通知,可以在添加BlackBox函数时关闭事件发送,从源头避免事件冲突:
def custom_blackbox(inputs): # 你的BlackBox计算逻辑 return output_values # 添加BlackBox函数时设置send_events=False model.add_blackbox_function(custom_blackbox, input_vars, output_vars, send_events=False)
注意事项
- 多Worker模式下,回调的
current_best和current_gap是在Worker进程中更新的,若需要跨进程共享数据,需使用multiprocessing模块的共享变量(如Value、Array)。 - 建议升级到最新版Docplex CP,部分旧版本的多进程回调存在已知Bug,升级后可能直接解决问题。
内容的提问来源于stack exchange,提问作者Yop
相关产品推荐
相关产品推荐

