我有一个顶级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")))
以下是我的问题:
如果我启动REPL并(run)
则启动并在后台线程中运行。当我退出REPL时,我看不到所需的关机消息。
但是,当我从lein run
开始运行时,go循环立即退出并显示“SHUTDOWN”。
这也不是我想要的。
我不一定希望找到适用于所有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,混合模式)
答案 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
放入内部也更好!)