第 8 章 OptaPlanner SolverManager
SolverManager
是一个或多个 Solver
实例的一个传真,以简化 REST 和其他企业服务中的潜在规划问题。
与 Solver.solve (…)
方法不同,S olverManager
具有以下特征:
-
SolverManager.solve (…)
会立即返回:它会调度一个异步问题,而不阻止调用线程。这可避免 HTTP 和其他技术的超时问题。 -
SolverManager.solve (…)
并行解决了同一域的多个规划问题。
在内部,SolverManager
管理一组解析程序线程,它调用 Solver.solve (…)
和消费者线程的线程池,它处理最佳解决方案更改了事件。
在 Quarkus 和 Spring Boot 中,SolverManager
实例会自动注入您的代码中。如果您使用 Quarkus 或 Spring Boot 以外的平台,请使用 create (…)
方法构建 SolverManager
实例:
SolverConfig solverConfig = SolverConfig.createFromXmlResource(".../cloudBalancingSolverConfig.xml"); SolverManager<CloudBalance, UUID> solverManager = SolverManager.create(solverConfig, new SolverManagerConfig());
提交到 Solver Manager.solve (…)方法的
每个问题都必须具有唯一的问题 ID。稍后调用 getSolverStatus (problemId)
或 killEarly (problemId)
使用该问题 ID 来区分规划问题。问题 ID 必须是不可变类,如 Long
、字符串
或 java.util.UUID
。
SolverManagerConfig
类有一个 parallelSolverCount
属性,用于控制并行运行多少解析程序。例如,如果 parallelSolverCount
属性设置为 4
,并且您提交了五个问题,则 4 个问题将立即开始,并且第五个问题在第一个问题结束时启动。如果这些问题每五分钟解决,则五个问题需要 10 分钟才能完成。默认情况下,parallelSolverCount
设置为 AUTO
,它将解析为 CPU 内核一半,而不考虑解析者的 moveThreadCount
。
要检索最佳解决方案,在参与后,通常会使用 SolverJob.getFinalBestSolution ()
:
CloudBalance problem1 = ...; UUID problemId = UUID.randomUUID(); // Returns immediately SolverJob<CloudBalance, UUID> solverJob = solverManager.solve(problemId, problem1); ... CloudBalance solution1; try { // Returns only after solving terminates solution1 = solverJob.getFinalBestSolution(); } catch (InterruptedException | ExecutionException e) { throw ...; }
但是,在用户需要解决方案以及用户主动等待解决方案时,在用户需要解决方案前,对业务批处理问题都有更好的方法。
当前 SolverManager
实施在一台计算机节点上运行,但将来的工作旨在在云中分发解析程序负载。
8.1. 批量问题
批量参与是并行多个数据集。批量参与对时间特别有用:
- 在每天的中间,通常有一些或没有问题更改。有些组织实施截止时间,例如,在周等 前提交所有一天的请求。
- resolvers 可以运行更长的时间(通常为几小时),因为 nobody 等待结果,CPU 资源通常较低。
- 当员工到达下一工作日时,可以使用相应的解决方案。
流程
要批量解决问题,受 parallelSolverCount
限制,请为每个数据集调用 solve (…)
创建以下类:
public class TimeTableService { private SolverManager<TimeTable, Long> solverManager; // Returns immediately, call it for every data set public void solveBatch(Long timeTableId) { solverManager.solve(timeTableId, // Called once, when solving starts this::findById, // Called once, when solving ends this::save); } public TimeTable findById(Long timeTableId) {...} public void save(TimeTable timeTable) {...} }