Optaplanner:并行求解时随机非常低 "average calcultate count per second"
Optaplanner: Randomly very low "average calcultate count per second" when solving in parallel
我正在使用 Optaplanner 解决一个相对较小的优化问题。对于我的用例,需要许多这样的优化,这就是为什么我开始并行 运行 它们的原因。并行性基于 Java 8' parallel stream
。它不允许控制要使用的实际线程数,但我相信它基于可用的 CPU 计数。
对于大多数求解器 运行s 这似乎工作正常,但我注意到有时我从单个 运行 得到无效的解决方案,当只有那个问题是 运行一个人.
检查日志后,我注意到 "average calculate count per second" 对于无效解决方案非常低,而对于其他 运行 则很好。事实上,无效的解决方案实际上是(天真地构建的)初始解决方案:
[rkJoinPool.commonPool-worker-6] (DefaultSolver.java:203) Solving started: time spent (0), best score (-5hard/-2medium/168soft), environment mode (REPRODUCIBLE), random (JDK with seed 0).
[rkJoinPool.commonPool-worker-6] (DefaultConstructionHeuristicPhase.java:158) Construction Heuristic phase (0) ended: step total (0), time spent (1), best score (-5hard/-2medium/233soft).
[rkJoinPool.commonPool-worker-4] (DefaultSolver.java:203) Solving started: time spent (1), best score (-5hard/-1medium/579soft), environment mode (REPRODUCIBLE), random (JDK with seed 0).
[rkJoinPool.commonPool-worker-4] (DefaultConstructionHeuristicPhase.java:158) Construction Heuristic phase (0) ended: step total (0), time spent (1), best score (-5hard/-1medium/617soft).
[rkJoinPool.commonPool-worker-5] (DefaultSolver.java:203) Solving started: time spent (1), best score (-6hard/-3medium/137soft), environment mode (REPRODUCIBLE), random (JDK with seed 0).
[rkJoinPool.commonPool-worker-7] (DefaultLocalSearchPhase.java:152) Local Search phase (1) ended: step total (42), time spent (704), best score (0hard/0medium/808soft).
[rkJoinPool.commonPool-worker-4] (DefaultLocalSearchPhase.java:152) Local Search phase (1) ended: step total (22), time spent (218), best score (0hard/0medium/1033soft).
[rkJoinPool.commonPool-worker-5] (DefaultSolver.java:238) Solving ended: time spent (210), best score (-6hard/-3medium/137soft), average calculate count per second (4), environment mode (REPRODUCIBLE).
[rkJoinPool.commonPool-worker-7] (DefaultSolver.java:238) Solving ended: time spent (746), best score (0hard/0medium/808soft), average calculate count per second (25256), environment mode (REPRODUCIBLE).
[rkJoinPool.commonPool-worker-4] (DefaultSolver.java:238) Solving ended: time spent (219), best score (0hard/0medium/1033soft), average calculate count per second (30461), environment mode (REPRODUCIBLE).
注意线程 4 和 7 如何使用 25-30k 的 accs 产生良好的结果,而线程 5 产生了无效的结果并且只使用了 4 个 accs(考虑到 200ms 的终止超时,我假设实际上只采取了一个步骤)。
使用了以下配置,这是使用基准程序确定的(尽管是在单线程设置中):
<termination>
<millisecondsSpentLimit>2000</millisecondsSpentLimit>
<unimprovedMillisecondsSpentLimit>200</unimprovedMillisecondsSpentLimit>
</termination>
<constructionHeuristic>
<constructionHeuristicType>FIRST_FIT</constructionHeuristicType>
</constructionHeuristic>
<localSearch>
<localSearchType>HILL_CLIMBING</localSearchType>
</localSearch>
我认为这个问题与以下事实有关:在使用基于时间的终止条件时,多个求解器并行 运行ning。终止时间是根据 "wall time" 还是实际 CPU 时间?
运行并行使用基于时间的终止标准不是个好主意吗?这似乎是使用所有可用计算能力的最佳方式。
是什么导致单个求解器看似随机地只执行这么少的步骤?
millisecondsSpentLimit
和 unimprovedMillisecondsSpentLimit
是基于墙上的时间,而不是实际的 CPU 时间。
AFAIK,并行流不会将线程数限制为 CPU 的数量,因为这些作业可能会在 IO 下阻塞(Solver.solve()
调用不是这种情况)。我更喜欢使用线程池大小为 Math.max(1, Runtime.getRuntime().availableProcessors() - 2)
的 ExecutorService
。
我正在使用 Optaplanner 解决一个相对较小的优化问题。对于我的用例,需要许多这样的优化,这就是为什么我开始并行 运行 它们的原因。并行性基于 Java 8' parallel stream
。它不允许控制要使用的实际线程数,但我相信它基于可用的 CPU 计数。
对于大多数求解器 运行s 这似乎工作正常,但我注意到有时我从单个 运行 得到无效的解决方案,当只有那个问题是 运行一个人.
检查日志后,我注意到 "average calculate count per second" 对于无效解决方案非常低,而对于其他 运行 则很好。事实上,无效的解决方案实际上是(天真地构建的)初始解决方案:
[rkJoinPool.commonPool-worker-6] (DefaultSolver.java:203) Solving started: time spent (0), best score (-5hard/-2medium/168soft), environment mode (REPRODUCIBLE), random (JDK with seed 0).
[rkJoinPool.commonPool-worker-6] (DefaultConstructionHeuristicPhase.java:158) Construction Heuristic phase (0) ended: step total (0), time spent (1), best score (-5hard/-2medium/233soft).
[rkJoinPool.commonPool-worker-4] (DefaultSolver.java:203) Solving started: time spent (1), best score (-5hard/-1medium/579soft), environment mode (REPRODUCIBLE), random (JDK with seed 0).
[rkJoinPool.commonPool-worker-4] (DefaultConstructionHeuristicPhase.java:158) Construction Heuristic phase (0) ended: step total (0), time spent (1), best score (-5hard/-1medium/617soft).
[rkJoinPool.commonPool-worker-5] (DefaultSolver.java:203) Solving started: time spent (1), best score (-6hard/-3medium/137soft), environment mode (REPRODUCIBLE), random (JDK with seed 0).
[rkJoinPool.commonPool-worker-7] (DefaultLocalSearchPhase.java:152) Local Search phase (1) ended: step total (42), time spent (704), best score (0hard/0medium/808soft).
[rkJoinPool.commonPool-worker-4] (DefaultLocalSearchPhase.java:152) Local Search phase (1) ended: step total (22), time spent (218), best score (0hard/0medium/1033soft).
[rkJoinPool.commonPool-worker-5] (DefaultSolver.java:238) Solving ended: time spent (210), best score (-6hard/-3medium/137soft), average calculate count per second (4), environment mode (REPRODUCIBLE).
[rkJoinPool.commonPool-worker-7] (DefaultSolver.java:238) Solving ended: time spent (746), best score (0hard/0medium/808soft), average calculate count per second (25256), environment mode (REPRODUCIBLE).
[rkJoinPool.commonPool-worker-4] (DefaultSolver.java:238) Solving ended: time spent (219), best score (0hard/0medium/1033soft), average calculate count per second (30461), environment mode (REPRODUCIBLE).
注意线程 4 和 7 如何使用 25-30k 的 accs 产生良好的结果,而线程 5 产生了无效的结果并且只使用了 4 个 accs(考虑到 200ms 的终止超时,我假设实际上只采取了一个步骤)。
使用了以下配置,这是使用基准程序确定的(尽管是在单线程设置中):
<termination>
<millisecondsSpentLimit>2000</millisecondsSpentLimit>
<unimprovedMillisecondsSpentLimit>200</unimprovedMillisecondsSpentLimit>
</termination>
<constructionHeuristic>
<constructionHeuristicType>FIRST_FIT</constructionHeuristicType>
</constructionHeuristic>
<localSearch>
<localSearchType>HILL_CLIMBING</localSearchType>
</localSearch>
我认为这个问题与以下事实有关:在使用基于时间的终止条件时,多个求解器并行 运行ning。终止时间是根据 "wall time" 还是实际 CPU 时间?
运行并行使用基于时间的终止标准不是个好主意吗?这似乎是使用所有可用计算能力的最佳方式。 是什么导致单个求解器看似随机地只执行这么少的步骤?
millisecondsSpentLimit
和 unimprovedMillisecondsSpentLimit
是基于墙上的时间,而不是实际的 CPU 时间。
AFAIK,并行流不会将线程数限制为 CPU 的数量,因为这些作业可能会在 IO 下阻塞(Solver.solve()
调用不是这种情况)。我更喜欢使用线程池大小为 Math.max(1, Runtime.getRuntime().availableProcessors() - 2)
的 ExecutorService
。