2012-07-17 54 views
16

我有很多Java字节码的例子,我想从Clojure执行所有这些例子。每个字节码序列可能包含一个无限循环,在这种情况下,我想在几秒钟后停止运行它。我一直在寻找期货作为这样做的一种手段。已经猎杀周围的一对夫妇实现的我都试过这个代码:为什么取消的Clojure期货继续使用CPU?

(deref (future (loop[a 1] (recur a)) :done!) 1000 :impatient!) 

...而且在https://gist.github.com/3124000

在这两种情况下的代码,循环似乎是适当的超时(和在后一种情况下,未来据报道已经完成并取消),但我看到我的CPU使用率上升到99%左右,并保持在那里。我还看到,每次运行此代码时,我的Java进程都会获得额外的线程。

它看起来像我未来被取消,但代码仍在运行。在我的程序中,我将需要运行并超时,出现一些非常紧密的无限循环(例如,“20 PRINT GOTO 10”的Java字节码等价物),并且我没有修改正在运行的代码的选项。

任何想法,为什么我看到这种行为;我能做些什么来阻止它;或替代方法让我实现我的目标,运行和超时此类代码?

回答

4

我发现实际杀死在线程内执行的代码的唯一方法是使用已弃用的.stop方法。在很多情况下,它被弃用的原因并不重要。

我在clojail中有这个功能。随意取出该功能或只需拉入库。

+0

这看起来确实很有用,但是当我这样做时(thunk-timeout(loop [a 0](recur a))10000)函数只是挂起而CPU上升...即使在10000ms之后也没有超时。有任何想法吗? – 2012-07-17 10:48:18

+0

我很快就说过了;当我创建一个ThreadGroup并将它传递给你的thunk-timeout时,一个循环函数确实停止了。谢谢:) – 2012-07-17 19:31:40

+0

为什么需要ThreadGroup,只需将它包装在fn中就足够了:) (thunk-timeout(fn [](loop [a 0](recur a))10000))) – o0omycomputero0o 2015-12-16 03:57:36

1

根据Java API文档,cancel没有授予能够立即停止工作。

试图取消对此任务的执行。如果任务已完成,已被取消或因其他原因无法取消,此尝试将失败。如果成功,并且此任务在调用取消时尚未开始,则此任务不应运行。如果任务已经启动,则mayInterruptIfRunning参数确定是否执行此任务的线程应该以试图停止任务被中断。

6

Java支持线程取消的机制是interrupts。该.stop()方法已被弃用的一个原因 - 见the docs,有效的Java,Java并发实践等

事实上,FutureTask实施(它备份future-cancel)是中断为主。

截至今天,每个Clojure的未来是由无界线程池(就像send-off行动)的支持。所以,你可以利用线程中断原语:

(def worker 
    (let [p (promise)] 
    {:future (future 
       (let [t (Thread/currentThread)] 
       (deliver p t) 
       (while (not (Thread/interrupted)) 
        (println 42) 
        (Thread/sleep 400)))) 
    :thread @p})) 

现在可以成功执行要么(.interrupt (:thread worker))(future-cancel (:future worker))

虽然这将线程取消机制与Futures的线程取消机制相结合,但可用的Executor实现足够智能以清除之前任务可能已设置的中断状态,因此对一个任务的中断不会影响其他任务 - 即使它们在同一个线程上运行。

问题是,抢先杀死线程通常是一个坏主意 - 如果你想取消任务,你必须以某种方式明确取消它们。 OTOH,在你的特定情况下你正在执行不透明的字节码,所以没有其他选择,只能采用.stop()