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)}
#  

这表明所有三个调用都在读取代理的状态,然后所有三个调用都在各自独立地添加读取的值

就这样!这就解决了问题。非常感谢你。