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

发布于 2024-10-21 14:09:59 字数 373 浏览 6 评论 0原文

创建一个在后台循环更新某些共享引用并管理其生命周期的线程的惯用 Clojure 方法是什么?我发现自己使用 future 来实现此目的,但这感觉有点像黑客,因为我从未返回有意义的值。例如:

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

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

What is the idiomatic Clojure way to create a thread that loops in the background doing updates to some shared refs and to manage its lifetime? I find myself using future for this, but it feels like a little bit of a hack as I never return a meaningful value. E.g.:

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

Also, I need to be careful to future-cancel this when the background processing is no longer needed. Any tips on how to orchestrate that in a Clojure/Swing application would be nice. E.g. a dummy JComponent that is added to my UI that is responsible for killing the thread when the window is closed may be an idea.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

但可醉心 2024-10-28 14:09:59

您的循环中不需要 do;这是暗示的。另外,虽然无条件循环递归没有任何问题,但您也可以使用 (while true ...)。

future 是一个很好的工具;不要因为永远得不到回报而烦恼。不过,如果您使用代理而不是未来,那么这确实会困扰您 - 没有价值观的代理是疯狂的。

然而,谁说你需要future-cancel?只需将您未来的步骤之一作为检查是否仍然需要它。然后代码的其他部分不需要跟踪 future 并决定何时取消它们。所以类似的方法

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

将是一种可行的方法。

You don't need a do in your loop; it's implied. Also, while there's nothing wrong with an unconditional loop-recur, you may as well use (while true ...).

future is a fine tool for this; don't let it bother you that you never get a value back. That should really bother you if you use an agent rather than a future, though - agents without values are madness.

However, who said you need to future-cancel? Just make one of the steps in your future be to check whether it's still needed. Then no other parts of your code need to keep track of futures and decide when to cancel them. So something like

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

would be a viable approach.

2024-10-28 14:09:59

使用代理执行后台重复任务对我来说似乎更简洁

(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

Using agents for background recurring tasks seems neater to me

(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)))

Now all you have to do is to initiate the loop

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

The my-backgound-task function is sending itself to the calling agent after its invocation is done.

This is the way how Rich Hickey performs recurring tasks in the ant colony example application: Clojure Concurrency

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文