2011-07-11 57 views
2

我使用代理來操縱結構,但我沒有所有的副作用。Clojure,代理,缺乏副作用

所有的信息都被髮送(我已經打印並統計了它們),但有時候我沒有全部的副作用。好像並非我的所有功能都應用於代理的狀態,或者如果最後一次發送應用於以前的狀態。

我嘗試過使用doall,dorun但未找到解決方案,非常感謝任何幫助。

;; aux function for adding an element to a hashmap 
(defn extend-regs [reg s o] 
    (let [os (get reg s)] 
    (if (nil? os) 
     (assoc reg s [o]) 
     (assoc reg s (conj os o))))) 

;; the agent's altering function - adding an element to the :regs field(a hashmap) 
(defn add-reg! [d s o] 
    (send d (fn [a] (assoc a :regs (extend-regs (:regs a) s o))))) 



;; Creating the agents, dct/init returns an agent 
;; pds: data for fields 
(defn pdcts->init-dcts! [pds] 
    (doall (map dct/init (map :nam pds) (repeat nil)))) 

;; Altering one agent's state, dct/add-reg sends an assoc message to the agent 
;; d: agent, pd: data for fields 
(defn dct->add-regs! [d pd] 
    (dorun (map (fn [s r] (dct/add-reg! d s r)) 
      (:syms pd) 
      (:regs pd))) 
    d) 

;; Going through all agents 
;; ds: agents, pds: datas 
(defn dcts->add-regs! [ds pds] 
    (dorun (map (fn [d pd] (dct->add-regs! d pd)) 
      ds 
      pds)) 
    ds) 

編輯:========================================= ============

好吧,事實證明我只是沒有足夠等待我的線程完成他們的任務。現在的問題是如何監控我的代理。我怎麼知道隊列中有未完成的線程?我只找到swank.core/活動線程和類似的,但它們不是解決方案。

+0

我還沒有測試過你的代碼,但是當你的函數被代理執行時你可能會得到一個異常。之後,代理將不會接受任何新命令並保持其狀態。您需要在代理上調用clojure.core/agent-error來返回異常,然後對異常執行clojure.repl/pst以獲取堆棧跟蹤。 – bmillare

+0

Thx回覆!我在失敗的案例上嘗試了代理錯誤,但是我得到了nils,所以沒有例外。無論如何thx! – argonz

回答

1

使用awaitawait-for等到代理完成它的當前工作隊列:

(await agent1 agent2 agent3) 

(apply await list-of-agents) 

附加REG的輕微改善:

(defn extend-regs [reg s o] 
    (update-in reg [s] conj o)) 

這工作,因爲

(conj nil :b)    ; => [:b] 

從而

(update-in {} [:a] conj :b) ; => {:a [:b]} 

最後我們。

(defn add-reg! [d s o] 
    (send d update-in s [:regs] conj o) 
2

我沒有你的問題的解決方案,但我不能抗拒提出一些改進的前兩個功能:

(defn extend-regs [reg s o] 
    (let [os (get reg s)] 
    (if (nil? os) 
     (assoc reg s [o]) 
     (assoc reg s (conj os o))))) 
;; => place the 'if inside the assoc: 
(defn extend-regs [reg s o] 
    (let [os (get reg s)] 
    (assoc reg s (if (nil? os) [o] (conj os o))))) 
;; => this (if (nil? x) ...) is the pattern of function fnil, so ... 
(defn extend-regs [reg s o] 
    (let [os (get reg s)] 
    (assoc reg s ((fnil conj []) os o)))) 
;; with update-in, this will be even clearer, and we can remove the let altogether: 
(defn extend-regs [reg s o] 
    (update-in reg [s] (fnil conj []) o)) 

至於第二:

(defn add-reg! [d s o] 
    (send d (fn [a] (assoc a :regs (extend-regs (:regs a) s o))))) 
;; => We can, again, use update-in instead of assoc: 
(defn add-reg! [d s o] 
    (send d (fn [a] (update-in a [:regs] extend-regs s o)))) 
;; or, if you can get rid of extend-regs: 
(defn add-reg! [d s o] 
    (send d (fn [a] (update-in a [:regs s] (fnil conj []) o))) 

最後,作爲一個風格問題,我會將add-reg放在一個單獨的函數中,並直接使用在客戶端代碼中發送給代理的方式(或者有一個簡化的add-reg!函數):

(defn add-reg [v s o] (update-in v [:regs s] (fnil conj []) o)) 

(defn add-reg! [d s o] (send d add-reg)) 

我知道這並不能回答你最初的問題,但很好玩寫這一步一步的重構

+0

是的,我不知道這些,thx指出他們!事實上,我剛剛發現,我的狀態沒有改變,因爲不是所有的線程都終止了,我沒有足夠的等待。 – argonz