【问题标题】:Gracefully exit a Clojure core.async go loop on kill优雅地退出 Clojure core.async go loop on kill
【发布时间】:2013-12-10 02:56:24
【问题描述】:

我有一个顶级的 core.async 循环。我希望它无限期地运行,至少在我用 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”。

两者都不是我想要的。

我不一定希望找到适用于所有 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,混合模式)

【问题讨论】:

标签: java clojure signals core.async


【解决方案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】:

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

    关于第2部分:go循环启动后,它在后台线程中运行。由于创建 go 块后主线程退出,因此程序关闭。要使循环长寿命,需要将其放入普通的loop。 (在里面放一个Thread/sleep 也更好!)

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 当您 (a) 从 REPL 运行时,您是否看到关闭消息; (b) 通过lein run运行?
      • 情况(a)lein repl没有关机信息,情况(b)lein run确实显示关机
      • 如果我在使用Ctrl-D 或使用(exit) 函数退出时运行lein trampoline repl 关机显示
      • 我不明白为什么这是一个公认的答案。这是错误的,因为从外部关闭 go 返回的通道不会停止 while-loop
      猜你喜欢
      • 2011-10-20
      • 1970-01-01
      • 1970-01-01
      • 2019-04-14
      • 2010-12-16
      • 1970-01-01
      • 1970-01-01
      • 2020-11-10
      • 2013-07-21
      相关资源
      最近更新 更多