记录Clojure代理

时间:2017-05-13 14:36:03

标签: logging clojure

我正在使用agents来设置处理链。我还想让记录器跟踪发生了什么。整个代码就在这里。

我可以看到:charlie msg已被处理,甚至会被打印到log函数... 在被“发送”为“conj”之后'ed'到记录器代理。

为什么查理永远不会出现在我的@logger

(def logger (agent []))  ;; logger to keep track of what's done

(defn log [msg]
  (send logger conj msg)  ;; charlie's msg is NOT conj'ed
  (println "logged" msg)) ;; but charilies msg IS printed

(defn create-relay [coll]
  (reduce (comp agent vector) nil (reverse coll)))  ;; see partial answer below

(defn relay-msg [next-agent prev-msg]
  (if (nil? next-agent)
    (log "finished relay")
    (let [new-msg (str prev-msg (second next-agent))]
      ;; do something interesting with new-msg then:
      (log new-msg)
      ;; go do the next thing
      (send (first next-agent) relay-msg new-msg))))

(send (create-relay [:alice :bob :charlie]) relay-msg "hello")
(. java.lang.Thread sleep 5000)
(prn @logger)

输出:

logged hello:alice
logged hello:alice:bob
logged hello:alice:bob:charlie
["hello:alice" "hello:alice:bob"]
;; expected last line to be:
;; ["hello:alice" "hello:alice:bob" "hello:alice:bob:charlie"]

部分答案 我已经找到了如何使它工作,但我仍然希望“接受”一个解释错误去哪里隐藏的答案。

印刷是一种副作用。代理是“一致”状态(无论这意味着什么)。在“记录”查理之后,下一行在此行中调用“send to nil”:

(send (first next-agent) relay-msg new-msg) ;; =>(first next-agent) is nil

似乎它应该是NullPointerException,但它永远不会出现。吞下因为它在另一个线程???

通过以下难以改变的方式修复:

(reduce (comp agent vector) nil (reverse coll))
;; => change to =>
(reduce (comp agent vector) (agent nil) (reverse coll))

为什么要对这个错误保持沉默? @logging回滚是否正确? 如果在回滚后有其他项目与logging“联合”怎么办?

我有“工作”代码,但我仍然迷失在这里的正确行为。 “联合国” - 记录的东西听起来很可怕。

1 个答案:

答案 0 :(得分:2)

答案可以在Clojure reference page for Agents上找到:

  
      
  1. 如果在功能执行期间(直接或间接)进行任何其他调度,它们将一直保持到代理状态发生变化之后。
  2.   

"其他调度"这实际上意味着调用send。因此,当为特定代理执行relay-msg时,对send的所有调用都会排队,直到relay-msg返回代理的新状态。在:alice:bob的情况下,一旦代理的状态更新,就会调度排队的send

但是,由于relay-msg上的:charlie会引发NullPointerException:charlie的代理会进入错误状态并排队send(包括<{1}}调用中的一个被丢弃。

  

似乎它应该是NullPointerException但它永远不会出现。因为它在另一个线程中被吞噬了???

排序。实际上,异常由代理调度机制封装。如果传递给log的函数抛出异常,则会捕获该异常并将代理置于错误状态。该例外存储在代理上,可以通过agent-error访问。 (此外,在失败的代理上对send的后续调用会抛出原始异常。)