现在,我需要在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))))
感谢。
答案 0 :(得分:2)
通常,您不希望代码重新加载会影响运行时。相反,您应该尝试使用e来寻找干净的方式来启动和关闭正在运行的应用程序代码。 G。 Malcolm Sparks的Stuart Sierras图书馆component
或juxt/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}}),但它是调用重载函数的必要条件。