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

Dav*_* J. 10 java signals clojure core.async

我有一个顶级的core.async go循环.我希望它无限期地运行,至少直到我用CTRL-C或杀死或类似信号来阻止它.我目前正在使用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")))
Run Code Online (Sandbox Code Playgroud)

这是我的问题:

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

  2. 但是,当我运行时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,混合模式)

小智 13

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

(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)))
Run Code Online (Sandbox Code Playgroud)

如果你只是close!通道,它不会停止循环运行。此外,不需要启动 go 块只是为了将值发送到 channel


edb*_*ond -2

go函数返回一个通道。您可能想要(close! chan)关闭钩子。

如果你运行,lein run你需要一个 main 函数来调用(run)来启动 go 线程。

(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)))
Run Code Online (Sandbox Code Playgroud)

  • 我不明白为什么这是一个被接受的答案。这是错误的,因为从外部关闭 `go` 返回的通道不会停止 while 循环 (20认同)