更新在线程中运行的clojure代码

时间:2014-01-16 18:20:57

标签: clojure reload

现在,我需要在clojure / java混音系统中重新加载某种代码。

我知道tools.namespace lib可以用来刷新clj代码。但是当我尝试重新加载线程中使用的代码时,它不会更新。

这是我需要更新的示例clojure代码:(只需在大写和小写之间切换。)

(ns com.test.test-util)
(defn get-word [sentence]
    (let [a-word (rand-nth (clojure.string/split sentence #"\s"))
        ;;a-word (clojure.string/upper-case a-word)
        ]
        (println a-word)
        a-word))

我用了一个未来来开始一个线程并调用上面的代码。

在main方法中,在我的第一次测试中,我只是创建了一个未来并在一段时间后刷新代码。但它没有更新。所以,我还测试了刷新后创建另一个线程。但是代码没有更新。

(defn start-job []
  (future (
            (println "start worker job.")
            (while @job-cond
              (do (get-word (rand-nth sentences))
                (Thread/sleep 2000)) )
            (println "return!")
            )))

(defn -main []
  (let [work-job (start-job)]
    (println "modify clj file...")
    (Thread/sleep 10000)
    (swap! job-cond not)
    (future-cancel work-job)
    (swap! job-cond not)

    (refresh)
    (Thread/sleep 3000)

    (let [new-work-job (start-job)]
      (Thread/sleep 10000)
      (swap! job-cond not)
      (future-cancel new-work-job))))

感谢。

1 个答案:

答案 0 :(得分:2)

通常,您不希望代码重新加载会影响运行时。相反,您应该尝试使用e来寻找干净的方式来启动和关闭正在运行的应用程序代码。 G。 Malcolm Sparks的Stuart Sierras图书馆componentjuxt/jig。然后仅在应用程序启动并运行时(或者至少不是运行代码的部分依赖于重命名的命名空间)重新加载命名空间。

话虽如此,这就是为什么你的例子不起作用的原因:

start-job无法在其生命周期内自动引用get-word的重新加载版本,因为它使用的get-work版本在编译时已解析。所以它仍然会使用旧版本。

使用

显式解析get-word的变量
(resolve `get-word)

并将返回的var作为函数调用,而不是将来直接使用get-word

接下来会发生什么? 完成更改并调用refresh后,-main仍将引用旧版本的start-job(因此,如果更改它,它将不会在运行时显示效果)。但是,get-word中的get-word将如上所述得到解决,并且将使用新版本的resolve

简短说明:您不能指望正在运行的已编译函数可以动态地重新加载自身(无论它是否在单独的线程上运行)。那将是(除非你在其中使用{{1}}),但它是调用重载函数的必要条件。