我正在使用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
“联合”怎么办?
我有“工作”代码,但我仍然迷失在这里的正确行为。 “联合国” - 记录的东西听起来很可怕。
答案 0 :(得分:2)
答案可以在Clojure reference page for Agents上找到:
- 如果在功能执行期间(直接或间接)进行任何其他调度,它们将一直保持到代理状态发生变化之后。
醇>
"其他调度"这实际上意味着调用send
。因此,当为特定代理执行relay-msg
时,对send
的所有调用都会排队,直到relay-msg
返回代理的新状态。在:alice
和:bob
的情况下,一旦代理的状态更新,就会调度排队的send
。
但是,由于relay-msg
上的:charlie
会引发NullPointerException
,:charlie
的代理会进入错误状态并排队send
(包括<{1}}调用中的一个被丢弃。
似乎它应该是NullPointerException但它永远不会出现。因为它在另一个线程中被吞噬了???
排序。实际上,异常由代理调度机制封装。如果传递给log
的函数抛出异常,则会捕获该异常并将代理置于错误状态。该例外存储在代理上,可以通过agent-error
访问。 (此外,在失败的代理上对send
的后续调用会抛出原始异常。)