我有一个程序使用状态空间搜索算法(A *,IDA *等)来解决一些问题。我想运行~30-50次测试迭代来获取一些信息(平均运行时间,扩展节点等),但我的问题是,有时这些算法可能需要很长时间才能解决问题。我想选择在方法调用上设置超时以限制执行时间(所以我可以在一夜之间运行测试并让它们可靠地完成)。
假设Solvers
(实现算法的类)按原样提供,不能更改。通过调用solve
方法来使用它们,该方法返回List<Integer>
。
这是我目前正在使用的代码的相关部分,由stackoverflow上的类似线程提供:
int nTests = 50;
long timeout = 120;
double[] expandedAvg = new double[solvers.size()]; // averages of expanded nodes for each solver
int[] fails = new int[solvers.size()]; // number of timeouts for each solver
for (int i = 1; i <= nTests; i++) {
int[][] problem = createProblem(); // creates a random solvable problem
int j = 0;
for (Solver solver : solvers) {
boolean success = true;
List<Integer> solution = null;
if (timeout > 0) {
Callable<List<Integer>> task = new Callable<List<Integer>>() {
@Override
public List<Integer> call() {
return solver.solve(problem);
}
};
Future<List<Integer>> future = Executors.newCachedThreadPool().submit(task);
try {
solution = future.get(timeout, TimeUnit.SECONDS);
}
catch (TimeoutException e) {
success = false;
System.out.println("FAIL");
}
catch (InterruptedException ignore) {}
catch (ExecutionException e) {
e.printStackTrace();
}
finally {
future.cancel(true);
}
}
else solution = solver.solve(problem);
if (success) {
// update the average
expandedAvg[j] = expandedAvg[j] + (solver.expanded - expandedAvg[j]) / (i - fails[j]);
}
else fails[j]++;
j++;
}
}
然而,最终发生的事情是,在第一次失败的求解尝试之后,所有进一步的尝试都失败了。问题似乎是future.cancel(true)
实际上并没有停止求解器的执行(我猜测整个应用程序在外循环结束后没有终止的事实,这意味着某些东西仍然存在然后在另一个线程中运行,然后占用所有资源,并且连续的那些资源不会获得任何CPU时间(并因此失败)。如果重要的话,我是从Eclipse运行的。
有没有办法确保线程在超时后停止?或者是否有其他方法可以实现我应该使用的超时?