【问题标题】:Logging a Clojure Agent记录 Clojure 代理
【发布时间】:2017-05-13 14:36:02
【问题描述】:

我正在使用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"]

部分回答 我已经找到了使它起作用的方法,但我仍在寻找“接受”一个答案,该答案解释了错误隐藏在哪里。

打印是一个副作用。代理处于“一致”状态(无论这意味着什么)。在 "logging" 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 回滚对吗?
如果回滚后还有其他项目“conj'ed”到 logging 怎么办?

我有“工作”代码,但我仍然对这里的正确行为感到迷茫。 “取消”记录某些内容听起来很可怕。

【问题讨论】:

    标签: logging clojure


    【解决方案1】:

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

    1. 如果在函数执行期间进行了任何其他调度(直接或间接),它们将被保留,直到代理的状态发生更改。

    这里的“其他调度”实质上是对send 的调用。因此,当为特定代理执行relay-msg 时,所有对send 的调用都会排队,直到relay-msg 返回代理的新状态。对于:alice:bob,一旦代理的状态更新,排队的sends 就会被调度。

    但由于relay-msg 上的relay-msg 抛出NullPointerException:charlie 的代理进入错误状态,排队的sends(包括对log 的调用中的那个)丢弃。

    似乎它应该是 NullPointerException 但它从未出现。被吞了,因为它在另一个线程中???

    有点。实际上,异常是由代理分派机制封装的。如果传递给send 的函数抛出异常,它会被捕获并且代理会进入错误状态。异常存储在代理上,可以通过agent-error 访问。 (此外,对失败代理的后续调用 send 会引发原始异常。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-07-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多