Clojure-一行中有多个发送的问题
我在代理和发送函数中遇到了一些非常奇怪的行为。我已经将这种行为归结为少量代码 此代码:Clojure-一行中有多个发送的问题,clojure,Clojure,我在代理和发送函数中遇到了一些非常奇怪的行为。我已经将这种行为归结为少量代码 此代码: (defn weird-behavior [] (let [my-agent (agent {:entries nil})] (doseq [entry [1 2 3]] (send my-agent assoc :entries (conj (@my-agent :entries) entry))) (Thread/sleep 100) ;; Allow time for
(defn weird-behavior
[]
(let [my-agent (agent {:entries nil})]
(doseq [entry [1 2 3]]
(send my-agent assoc :entries (conj (@my-agent :entries) entry)))
(Thread/sleep 100) ;; Allow time for the sends to finish
(println my-agent)))
产出:
#<Agent@222e8b4: {:entries (3)}>
产出如预期:
#<Agent@6211e63b: {:entries (3 2 1)}>
#
为什么会这样?如何将一行中的多个项目发送到代理
谢谢。问题是您在操作之外对代理进行了
deref
引用,因此当将代理的当前值作为参数传递给send
时,排队等待代理的所有操作都会收到相同的值(即nil
)
您可以在中使用update以避免deref
引用值:
(定义奇怪的行为
[]
(让[我的代理人(代理人{:无)})]
(doseq[条目[1 2 3]]
(在[:entries]conj entry]中发送我的代理更新)
(线程/睡眠100);;等待发送完成
(我的代理人)
;= #
发送的调度操作是代理当前状态的函数。这可能有助于明确这一点,这样您就不会试图自己取消对它的引用
(defn weird-behavior []
(let [my-agent (agent {:entries nil})]
(doseq [entry [1 2 3]]
(send my-agent
(fn [state]
(merge-with conj state {:entries entry}))))
(await my-agent)
(println my-agent)))
这个问题可以通过让发送给代理的函数打印它要附加的值来说明。如果不只是调用assoc
,而是使用println组成此函数,以便它打印值,那么您可以清楚地看到有无休眠的函数之间的差异:
(let [my-agent (agent {:entries nil})]
(doseq [entry [1 2 3]]
(send my-agent (comp #(do (println "adding entry" %) %)
assoc)
:entries (conj (@my-agent :entries) entry)))
(Thread/sleep 100) ;; Allow time for the sends to finish
(println my-agent))
adding entry {:entries (1)}
adding entry {:entries (2)}
adding entry {:entries (3)}
#<Agent@75bee6fc: {:entries (3)}>
(let [my-agent (agent {:entries nil})]
(doseq [entry [1 2 3]]
(send my-agent (comp #(do (println "adding entry" %) %)
assoc)
:entries (conj (@my-agent :entries) entry))
(Thread/sleep 10))
(Thread/sleep 100) ;; Allow time for the sends to finish
(println my-agent))
adding entry {:entries (1)}
adding entry {:entries (2 1)}
adding entry {:entries (3 2 1)}
#<Agent@1c36ee92: {:entries (3 2 1)}>
(让[我的代理(代理{:entries nil})]
(doseq[条目[1 2 3]]
(发送我的代理(comp#)(do(println“adding entry”%”)%)
协会)
:条目(conj(@my-agent:entries)条目)
(线程/睡眠100);;等待发送完成
(我的代理人)
添加条目{:条目(1)}
添加条目{:条目(2)}
添加条目{:条目(3)}
#
与具有睡眠的版本相比:
(let [my-agent (agent {:entries nil})]
(doseq [entry [1 2 3]]
(send my-agent (comp #(do (println "adding entry" %) %)
assoc)
:entries (conj (@my-agent :entries) entry)))
(Thread/sleep 100) ;; Allow time for the sends to finish
(println my-agent))
adding entry {:entries (1)}
adding entry {:entries (2)}
adding entry {:entries (3)}
#<Agent@75bee6fc: {:entries (3)}>
(let [my-agent (agent {:entries nil})]
(doseq [entry [1 2 3]]
(send my-agent (comp #(do (println "adding entry" %) %)
assoc)
:entries (conj (@my-agent :entries) entry))
(Thread/sleep 10))
(Thread/sleep 100) ;; Allow time for the sends to finish
(println my-agent))
adding entry {:entries (1)}
adding entry {:entries (2 1)}
adding entry {:entries (3 2 1)}
#<Agent@1c36ee92: {:entries (3 2 1)}>
(让[我的代理(代理{:entries nil})]
(doseq[条目[1 2 3]]
(发送我的代理(comp#)(do(println“adding entry”%”)%)
协会)
:条目(conj(@my-agent:entries)条目)
(线程/睡眠10))
(线程/睡眠100);;等待发送完成
(我的代理人)
添加条目{:条目(1)}
添加条目{:条目(2 1)}
添加条目{:条目(3 2 1)}
#
这表明所有三个调用都在读取代理的状态,然后所有三个调用都在各自独立地添加读取的值 就这样!这就解决了问题。非常感谢你。