执行在超时后返回的长计算 [英] Performing a long calculation that returns after a timeout

查看:122
本文介绍了执行在超时后返回的长计算的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用迭代深化来执行搜索,这意味着每次我做,我会更深,它需要更长的时间。有一个时间限制(2秒),以获得最好的结果。从我研究过的,最好的方法是使用ExecutorService,未来,并在时间用完时中断它。这是我现在的时间:

I want to perform a search using iterative deepening, meaning every time I do it, I go deeper and it takes longer. There is a time limit (2 seconds) to get the best result possible. From what I've researched, the best way to do this is using an ExecutorService, a Future and interrupting it when the time runs out. This is what I have at the moment:

在我的主要功能:

ExecutorService service = Executors.newSingleThreadExecutor();
ab = new AB();
Future<Integer> f = service.submit(ab);
Integer x = 0;
try {
    x = f.get(1990, TimeUnit.MILLISECONDS);
}
catch(TimeoutException e) {
    System.out.println("cancelling future");
    f.cancel(true);
}
catch(Exception e) {
    throw new RuntimeException(e);
}
finally {
    service.shutdown();
}
System.out.println(x);

和Callable:

public class AB implements Callable<Integer> {

    public AB() {}

    public Integer call() throws Exception {
        Integer x = 0;
        int i = 0;
        while (!Thread.interrupted()) {
            x = doLongComputation(i);
            i++;
        }
        return x;
    }
}

我有两个问题:


  1. doLongComputation()没有被中断,程序仅在完成工作后检查Thread.interrupted()是否为true。我需要在doLongComputation()中检查以查看线程是否已被中断?

  2. 即使我摆脱了doLongComputation(),主方法没有接收值的x。如何确保我的程序等待Callable清理并返回最好的x到目前为止?


推荐答案

要回答第1部分:是的,您需要让您的长任务检查中断标志。

To answer part 1: Yes, you need to have your long task check the interrupted flag. Interruption requires the cooperation of the task being interrupted.

还需要使用 Thread.currentThread()。isInterrupted()除非你特别想要清除中断标志。代码抛出(或重新抛出)InterruptedException使用线程#中断作为一种方便的方法来检查标志并清除它,当你写一个Runnable或Callable时,这通常不是你想要的。

Also you should use Thread.currentThread().isInterrupted() unless you specifically want to clear the interrupt flag. Code that throws (or rethrows) InterruptedException uses Thread#interrupted as a convenient way to both check the flag and clear it, when you're writing a Runnable or Callable this is usually not what you want.

现在回答第2部分:取消不是你想要的。

Now to answer part 2: Cancellation isn't what you want here.

使用取消停止计算并返回中间结果不起作用,一旦取消未来,您就无法从get方法检索返回值。你可以做的是使计算的每个细化自己的任务,所以你提交一个任务,获得结果,然后提交下一个使用结果作为起点,保存最新的结果,你去。

Using cancellation to stop the computation and return an intermediate result doesn't work, once you cancel the future you can't retrieve the return value from the get method. What you could do is make each refinement of the computation its own task, so that you submit one task, get the result, then submit the next using the result as a starting point, saving the latest result as you go.

下面是一个演示这个例子的例子,使用牛顿法计算平方根的逐次逼近。每个迭代是一个单独的任务,当前一个任务完成时,它将被提交(使用上一个任务的近似):

Here's an example I came up with to demonstrate this, calculating successive approximations of a square root using Newton's method. Each iteration is a separate task which gets submitted (using the previous task's approximation) when the previous task completes:

import java.util.concurrent.*;
import java.math.*;

public class IterativeCalculation {

    static class SqrtResult {
        public final BigDecimal value;
        public final Future<SqrtResult> next;
        public SqrtResult(BigDecimal value, Future<SqrtResult> next) {
            this.value = value;
            this.next = next;
        }
    }

    static class SqrtIteration implements Callable<SqrtResult> {
        private final BigDecimal x;
        private final BigDecimal guess;
        private final ExecutorService xs;
        public SqrtIteration(BigDecimal x, BigDecimal guess, ExecutorService xs) {
            this.x = x;
            this.guess = guess; 
            this.xs = xs;
        }

        public SqrtResult call() {
            BigDecimal nextGuess = guess.subtract(guess.pow(2).subtract(x).divide(new BigDecimal(2).multiply(guess), RoundingMode.HALF_EVEN));
            return new SqrtResult(nextGuess, xs.submit(new SqrtIteration(x, nextGuess, xs)));
        }
    }

    public static void main(String[] args) throws Exception {
        long timeLimit = 10000L;
        ExecutorService xs = Executors.newSingleThreadExecutor();
        try {
            long startTime = System.currentTimeMillis();
            Future<SqrtResult> f = xs.submit(new SqrtIteration(new BigDecimal("612.00"), new BigDecimal("10.00"), xs));
            for (int i = 0; System.currentTimeMillis() - startTime < timeLimit; i++) {
                f = f.get().next;                
                System.out.println("iteration=" + i + ", value=" + f.get().value);
            }
            f.cancel(true);
        } finally {
            xs.shutdown();
        }
    }
}

这篇关于执行在超时后返回的长计算的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆