更新线程中运行的clojure代码
现在,我需要在clojure/java混合系统中重新加载某种代码 我知道tools.namespace lib可以用来刷新clj代码。但当我尝试重新加载线程中使用的代码时,它不会被更新更新线程中运行的clojure代码,clojure,reload,Clojure,Reload,现在,我需要在clojure/java混合系统中重新加载某种代码 我知道tools.namespace lib可以用来刷新clj代码。但当我尝试重新加载线程中使用的代码时,它不会被更新 (defn start-job [] (future ( (println "start worker job.") (while @job-cond (do (get-word (rand-nth sentences))
(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))))
这是我需要更新的clojure代码示例:(只需在大写和小写之间切换)
我使用future来启动一个线程并调用上面的代码
在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))))
谢谢。通常,您不希望代码重新加载影响运行时。相反,您应该尝试寻找干净的方法来使用e引导和关闭正在运行的应用程序代码。GStuart Sierras library
组件
或Malcolm Sparks的juxt/jig。然后,仅当应用程序未启动并运行时(或者至少不是依赖于重新加载的名称空间的运行代码部分)才重新加载名称空间
尽管如此,以下是您的示例不起作用的原因:
start job
无法在其生存期内自动引用重新加载的get word
版本,因为它使用的get work
版本在编译时已解析。因此,它仍将使用旧版本
使用
(resolve `get-word)
并将返回的var作为函数调用,而不是将来直接使用get word
那么会发生什么?
在您进行更改并且调用了刷新
之后,-main
仍将引用旧版本的启动作业
(因此,如果您更改该版本,它将不会在运行时显示效果)。但是,在该范围内,get word
将按上述方式进行解析,并将使用新版本的get word
简短解释:您不能期望正在运行的编译函数在运行时用重新加载的代码替换自身(无论它是否在单独的线程上运行)。这将(除非您在其中使用
resolve
)是它调用重新加载的函数的必要条件。您有额外的括号,保证会在启动作业定义中导致NPE。无引号的括号不会对clojure中的代码块进行分组,而是调用函数或宏调用。Future有一个隐式do块,所以不需要将代码块包装在Future中。另外,while块中的do是不需要的,因为while也有一个隐式do。我认为您可以期望动态地重新加载代码,这取决于技术。例如,在环形应用程序中,传递“#var”作为处理程序是一种常见的习惯用法,比如runjetty'#app
而不是runjetty app
。因此,如果您更改var引用的函数并重新评估var,您将立即获得新代码。您可以重新评估。不过,对于重新加载名称空间来说,这是行不通的。重新评估意味着您只需在当前环境中重新评估表单,这意味着将调用defn
,这只会改变var的根绑定。如果您传递的是var而不是函数,则在调用之前将查找它的根绑定。但是,如果您正在重新加载名称空间,var(包括其根绑定)将被忘记(连同包含它的名称空间类),并且您只能在新加载的名称空间中找到新版本。谢谢。我计划使用Stuart Sierras的组件库重新加载worker。并在重置之前刷新代码。