OptaPlanner中调整Shadow Variables更新时机及优化工作解决方案状态追踪的技术问询
解决方案:优化云平衡问题中Move Selector的状态追踪性能
针对你在云平衡场景下遇到的「shadow变量更新过于频繁导致性能下降」的问题,我整理了几个针对性的优化方案,既可以保留增量计算的优势,又能避免不必要的状态更新:
1. 自定义缓存替代Shadow变量(推荐)
既然你不需要shadow变量参与评分,完全可以自己维护一个独立的状态缓存,只在接受移动操作后更新它,而非每次试探性移动都触发更新:
- 实现思路:
- 创建一个类(比如
ComputerLoadCache),内部用Map<Computer, Integer>存储每台计算机的进程数 - 在你的Solver配置中添加一个
PhaseLifecycleListener,监听STEP_ENDED事件——每当步骤结束(即接受了某个移动操作),就根据当前的working solution增量更新这个缓存(比如移除旧进程所在计算机的计数,增加新进程所在计算机的计数) - 在你的
SelectionProbabilityWeightFactory实现中,直接读取这个缓存的数值来计算权重,不用依赖shadow变量
- 创建一个类(比如
这种方式完全避开了shadow变量的自动更新机制,把状态更新的控制权牢牢握在自己手里,既能享受增量计算的高效,又不会在试探性移动时做无用功。
2. 调整Shadow变量的触发策略(如果必须用Shadow变量)
OptaPlanner默认会在每次working solution变更时更新shadow变量,但你可以通过自定义VariableListener来控制更新时机:
- 自定义一个继承自
AbstractVariableListener的实现,重写afterVariableChanged方法 - 在方法内部添加判断:只有当当前的移动是已被接受的最终移动时,才执行shadow变量的更新逻辑
- 怎么判断移动是否被接受?你可以通过
ScoreDirector的getWorkingSolution结合Solver的状态,或者在PhaseLifecycleListener的STEP_ENDING事件中标记当前步骤的有效移动,让VariableListener只响应这个有效移动的变更
不过这个方法相对复杂,因为需要和Solver的生命周期事件联动,不如第一种方案直接。
3. 优化Move Factory的增量计算
如果你考虑用自定义Move Factory,也不用每次全量计算计算机的进程数:
- 在Move Factory内部维护一个和方案1类似的缓存,每次生成Move前先检查缓存是否有效(比如标记是否有步骤更新过)
- 如果缓存有效,直接用缓存数值计算权重;如果无效(比如刚进入新步骤),再一次性计算所有计算机的进程数并更新缓存
- 同样在
STEP_ENDED事件中更新缓存,保证缓存和working solution的一致性
这样既保留了Move Factory的灵活性,又避免了重复的全量计算,性能和shadow变量的增量更新相差无几。
总结下来,第一种自定义缓存的方案是最简洁高效的,既满足了Move Selector对状态的需求,又彻底解决了shadow变量过度更新的性能问题。
内容的提问来源于stack exchange,提问作者B Myers
相关产品推荐
相关产品推荐

