2014-01-16 22 views
0

现在,我需要在clojure/java混合系统中重新加载一些代码。更新在线程中运行的clojure代码

我知道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)) 

我使用的将来启动一个线程并调用上述代码。

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

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

谢谢。

+2

您有多余的括号可保证在开始作业定义中导致NPE。不带引号的括号不会将代码块分组到clojure中,它们会调用函数或宏调用。未来有一个隐含的do块,所以你不需要在未来包装代码块。同时块中的do也是不需要的,因为while也有一个隐含的do。 – noisesmith

回答

2

一般而言,您不希望代码重新加载影响运行时。相反,您应该尝试寻求干净的方法来使用e来启动和关闭正在运行的应用程序代码。 G。 Stuart Sierras图书馆componentjuxt/jig Malcolm Sparks。然后,只有当您的应用程序不是启动并运行(或至少不是依赖名称空间正在重新加载的运行代码部分)时,才会重新加载命名空间。

话虽这么说,这里就是为什么你的例子不工作:

start-job不能自动指的get-word一个重载版本在其生命周期,因为当它被编译的get-work它使用的版本得到解决。所以它仍然会使用旧版本。

使用

(resolve `get-word) 

明确解决的get-word var和调用返回var当成一个函数,而不是直接在将来使用get-word

然后会发生什么? 完成更改并调用refresh后,-main仍将引用start-job的旧版本(因此如果更改该版本,则不会在运行时显示效果)。但是,get-word将在上面解释,并将使用新版本get-word

简短解释:你不能指望一个正在运行的编译函数在运行中用重载代码替换自己(不管它是否在单独的线程上运行)。这将(除非你使用resolve)是必要的,但它会调用重载函数。

+0

我想你可以期望重新加载代码,它只取决于技术。例如,在Ring应用程序中通常会使用'#var作为处理程序,如'run-jetty'#app'而不是'run-jetty app'。所以,如果你改变var引用的函数并重新评估var,你将会获得新的代码。 – georgek

+0

你是重新评估的权利。不过,对于重新加载名称空间来说,它不起作用。重新评估意味着您只需在当前环境中重新评估表单,这意味着'defn'将被调用,只会改变var的根绑定。如果你传递一个var而不是一个函数,它会在调用之前查找根绑定。但是,如果将此重装命名空间中,VAR(包括其根结合)会被遗忘(包含它的命名空间一起上课),你只能在新加载的命名空间中找到了新的版本。 –

+0

谢谢。 我正在计划使用Stuart Sierras的组件库来重新加载工人。重置之前刷新代码。 – Mavlarn