OptaPlanner规划实体变更时如何失效重算任务跨度与开始时间
OptaPlanner等待跨度逻辑优化与影子变量自动更新方案
更优的等待跨度实现思路
不要将任务启动时间拆分为「初始计算时间+等待跨度」两个独立存储的字段,从根源上避免缓存不一致问题:
- 直接将
startTime设为任务唯一的时间类影子变量,跨度值不需要持久化存储,需要时通过startTime - 任务最早可启动时间临时计算即可。 - 不要按机器维度单独统计员工占用,维护全局的员工资源占用区间结构(推荐用区间树或者事件点集合,不要逐时间片计数),计算任务启动时间时,从任务的最早可启动时间开始,只校验所有已有任务的开始/结束时间点,找到第一个同时满足「分配的机器处于空闲状态」「当前时间点剩余可用员工数满足任务要求」的时间点,直接赋值给
startTime即可。 - 该方案不需要额外维护跨度缓存,不存在前置任务变更后旧跨度值失效的问题,同时因为只校验事件点、不需要遍历全量任务逐时间片判断,性能远高于原有全量遍历逻辑。
沿用现有实现的影子变量自动重算配置方法
不需要自己实现「单实体变更触发全量更新」的逻辑,直接利用OptaPlanner原生的变量监听器做增量更新即可,性能不会出现明显衰减:
- 首先为
startTime、waitSpan两个影子变量配置独立的VariableListener,明确声明变量的所有依赖源:包括任务分配的机器实例、当前机器上的前置任务序列、全局员工占用计数。核心配置示例如下:@ShadowVariable( variableListenerRef = @VariableListenerRef(entityClass = Task.class, value = "startTime") ) private Long startTime; @ShadowVariable( variableListenerRef = @VariableListenerRef(entityClass = Task.class, value = "waitSpan") ) private Long waitSpan; - 实现
VariableListener的变更回调方法时,严格执行增量更新逻辑,绝对不要全量遍历所有实体:- 当某个任务的分配机器、执行顺序、执行时长发生变更时,先定位到该任务变更影响的时间区间,只筛选出启动时间落在该影响区间内、存在员工资源竞争可能的任务加入重算队列,和该变更完全时间不重叠、资源不冲突的任务直接跳过。
- 重算前先把待重算任务按时间先后排序,从早到晚依次重新计算startTime和waitSpan,每计算完一个任务就同步更新全局员工占用计数,如果某个任务重算后的值和旧值完全一致,直接终止该分支后续的连锁重算,避免无意义的计算。
- 这类增量更新的逻辑和OptaPlanner原生的增量评分机制逻辑对齐,不会出现全量更新带来的性能指数级衰减问题,同时能保证任何move操作后,所有影子变量都会自动触发精准重算,不会残留旧的无效值。
内容的提问来源于stack exchange,提问作者Vasco Ferreira
相关产品推荐
相关产品推荐

