用于生成和管理后台线程的惯用Clojure方法

时间:2011-03-13 18:28:52

标签: multithreading swing clojure dispose ownership

什么是惯用的Clojure方法来创建一个在后台循环的线程,对某些共享引用进行更新并管理它的生命周期?我发现自己正在使用future,但感觉有点像黑客,因为我永远不会返回有意义的值。 E.g:

(future (loop [] (do
    (Thread/sleep 100)
    (dosync (...))
    (recur))))

另外,当不再需要后台处理时,我需要小心future-cancel这个。关于如何在Clojure / Swing应用程序中编排它的任何提示都会很好。例如。添加到我的UI中的虚拟JComponent可能是一个想法。

是一个负责在窗口关闭时杀死线程的虚拟{{1}}。

2 个答案:

答案 0 :(得分:9)

你的循环中不需要do;这是隐含的。此外,虽然无条件循环复发没有任何问题,但您也可以使用(而真实......)。

future是一个很好的工具;不要让你觉得你永远不会得到回报。如果你使用代理而不是未来,这应该真的打扰你 - 尽管 - 没有价值观的代理商是疯狂的。

然而,谁说你需要future-cancel?只需在将来的一个步骤中检查是否仍然需要它。然后,您的代码中没有其他部分需要跟踪期货并决定何时取消它们。像

这样的东西
(future (loop []
          (Thread/sleep 100)
          (when (dosync
                 (alter some-value some-function))
            (recur)) ; quit if alter returns nil
          ))

将是一种可行的方法。

答案 1 :(得分:0)

使用代理进行后台重复性任务似乎更适合我

(def my-ref (ref 0))

(def my-agent (agent nil))

(defn my-background-task [x]
  (do
    (send-off *agent* my-background-task)
    (println (str "Before " @my-ref))
    (dosync (alter my-ref inc))
    (println "After " @my-ref)
    (Thread/sleep 1000)))

现在你所要做的就是启动循环

(send-off my-agent my-background-task)

my-backgound-task函数在调用完成后将自身发送给调用代理。

这就是Rich Hickey在蚁群示例应用程序中执行重复任务的方式:Clojure Concurrency