为什么取消的Clojure期货继续使用CPU?

Tom*_*ume 18 cpu profiling timeout future clojure

我有很多Java字节码的例子,我想从Clojure执行所有这些例子.每个字节码序列可能包含一个无限循环,在这种情况下,我想在几秒钟后停止运行它.我一直在期待将期货作为一种手段.在寻找几个实现后,我尝试了这两个代码:

(deref (future (loop[a 1] (recur a)) :done!) 1000 :impatient!)
Run Code Online (Sandbox Code Playgroud)

......以及https://gist.github.com/3124000上的代码

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

在我看来,未来正在取消,但代码仍在运行.在我的程序中,我将需要运行和超时,一些非常紧密的无限循环(例如,相当于"20 PRINT GOTO 10"的Java字节码),我没有选择修改我正在运行的代码.

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

vem*_*emv 8

Java支持的线程取消机制是中断..stop()不推荐使用该方法是有原因的 - 请参阅文档,Effective Java,Java Concurrency in Practice等.

实际上,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}))
Run Code Online (Sandbox Code Playgroud)

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

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

重点是先发制人地杀死线程通常是一个坏主意 - 如果你想取消任务,你必须以某种或其他方式明确地取消它们.OTOH,在您的特定情况下,您正在执行不透明的字节码,因此没有其他选择而不是诉诸.stop().


Ray*_*yne 4

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

我在clojail中有一个函数可以做到这一点。请随意提取该函数或直接拉入库。