优雅地退出Clojure core.async循环杀死

时间:2013-12-10 02:56:24

标签: java clojure signals core.async

我有一个顶级core.async go循环。我希望它能无限期地运行,至少在我用CTRL-C或kill或类似信号表示它停止之前。我目前正在使用这样的java.lang.Runtime/addShutdownHook

(ns async-demo.core
  (:require [clojure.core.async :as async
             :refer [<! >! <!! timeout chan alt! go]]))
(defn run [] (go (loop [] (recur))))
(.addShutdownHook (Runtime/getRuntime) (Thread. #(println "SHUTDOWN")))

以下是我的问题:

  1. 如果我启动REPL并(run)则启动并在后台线程中运行。当我退出REPL时,我看不到所需的关机消息。

  2. 但是,当我从lein run开始运行时,go循环立即退出并显示“SHUTDOWN”。

  3. 这也不是我想要的。

    我不一定希望找到适用于所有JVM的解决方案。我在Mac上开发并部署到Ubuntu,所以我想找到适合两者的解决方案:

    • Mac JVM:java版“1.7.0_45”Java(TM)SE运行时环境(版本1.7.0_45-b18)Java HotSpot(TM)64位服务器VM(版本24.45-b08,混合模式)

    • Ubuntu JVM:java版“1.7.0_25”OpenJDK运行时环境(IcedTea 2.3.10)(7u25-2.3.10-1ubuntu0.12.04.2)OpenJDK 64位服务器VM(版本23.7-b01,混合模式)

3 个答案:

答案 0 :(得分:1)

go函数返回一个频道。您可能希望在关机挂钩中(close! chan)

如果你运行lein run,你需要一个主函数,它会调用(run)开始去线程。

(ns async-demo.core
  (:require [clojure.core.async :as async
             :refer [<! >! <!! timeout chan alt! go close!]]))

(def ch (atom nil))

(defn run []
  (go (while true
        (<! (timeout 500))
        (prn "inside go"))))

(defn -main [& args]
  (println "Starting")
  (reset! ch (run))
  (.addShutdownHook (Runtime/getRuntime)
                    (Thread. #(do
                                (println "SHUTDOWN")
                                (close! @ch))))
  (while true
    (<!! @ch)))

答案 1 :(得分:1)

您可以使用信令exit-ch并执行条件查看是否应退出循环。通过alt!在clojure中可以更好地处理通道+条件:

(ns async-demo.core
  (:require [clojure.core.async :refer [chan go-loop alt! timeout put!]]))

(defn run
  []
  (let [exit-ch (chan)]
    (go-loop []
      (alt!
         (timeout 10) (recur)
         exit-ch nil
    exit-ch

(let [exit-ch (run)]
  (.addShutdownHook (Runtime/getRuntime) (put! exit-ch true)))

如果您只是close!频道,它不会停止循环的运行。另外,don't need to start a go block just to send a value to a channel

答案 2 :(得分:-2)

关于第1部分:“当我退出REPL时,我看不到所需的关闭消息。”我认为关闭线程没有连接到lein repl的控制台。

关于第2部分:在开始循环之后,它在后台线程中运行。由于主线程在创建go块后退出,程序将关闭。为了使循环长寿,需要将其置于正常loop。 (将Thread/sleep放入内部也更好!)