2017-03-20 36 views
1

我正在嘗試在事務中使用send-off函數printlnclojure sendoff println函數

(ns com.lapots.functional.clojure.transact 
    (:gen-class)) 

(defn transfer [from to amount] 
    (alter 
     (.balance from) - amount) 
    (alter 
     (.balance from) + amount)) 

(defrecord Account [balance]) 

(defn -main [& args] 
    (def account1 (Account. (ref 100))) 
    (def account2 (Account. (ref 100))) 
    (def trx-agent (agent 0)) 

    (future 
     (dosync 
      (send-off trx-agent println "T2 transfer") 
      (Thread/sleep 5000) 
      (transfer account1 account2 10))) 

    (dosync 
     (println "T1 transfer") 
     (transfer account1 account2 10)) 

    (shutdown-agents) 
) 

如果我不喜歡這個

(println "T2 transfer") 
(Thread/sleep 5000) 

它會顯示消息兩倍的交易重試。所以我決定使用agents使副作用運行println只運行一次。

但是當我做這樣的

(send-off trx-agent println "T2 transfer") 

它不會在所有打印T2 transfer消息。問題是什麼?

回答

1

您正在使用shutdown-agents過早。

(defn transfer [from to amount] 
    (println :transfer-enter amount) 
    (alter 
    (.balance from) - amount) 
    (alter 
    (.balance from) + amount) 
    (println :transfer-exit amount) 
) 

(defrecord Account [balance]) 

(def account1 (Account. (ref 100))) 
(def account2 (Account. (ref 100))) 
(def trx-agent (agent 0)) 

(defn -main [& args] 
    (println :main-enter) 

    (future 
    (dosync 
     (println :t2-enter) 
     (send-off trx-agent println "agent: T2 transfer") 
     (Thread/sleep 500) 
     (transfer account1 account2 20) 
     (println :t2-exit) 
    )) 

    (dosync 
    (println :t1-enter) 
    (send-off trx-agent println "agent: T1 transfer") 
    (transfer account1 account2 10) 
    (println :t1-exit)) 

    (Thread/sleep 2000) 
    (shutdown-agents) 
    (println :main-exit) 
) 

與結果:

:main-enter 
:t2-enter 
:t1-enter 
:transfer-enter 10 
:transfer-exit 10 
:t1-exit 
0 agent: T1 transfer 
:transfer-enter 20 
:t2-enter 
:transfer-enter 20 
:transfer-exit 20 
:t2-exit 
nil agent: T2 transfer 
:main-exit 

所以T2只能等待500毫秒現在,而T1運行的時候了。我們等待2000毫秒,然後調用shutdown-agents,這將終止所有代理線程,防止代理運行。

+0

哦,我明白了。基本上在調用'println transfer'之前,我等待10秒鐘(事務重試),但在提交時代理已關閉 – lapots

1

我看到至少有三件事情錯了你的代碼片段:

  1. transfer功能

    (defn transfer [from to amount] 
        (alter 
        (.balance from) - amount) ;; <======== from - amount 
        (alter 
        (.balance from) + amount)) ;; <======== from + amount 
    

    看起來你其實想說的改變from,然後改變to

  2. 來自send-off文檔:

    向代理髮送潛在阻塞操作。立即返回代理 。隨後,在一個單獨的線程,該 代理的狀態將被設置爲的值:(適用行動-FN劑國家的 參數)

    所以我認爲你不需要未來。還行

    (send-off trx-agent println "T2 transfer") 
    

    意味着你代理的狀態設置爲的

    (println state-of-agent "T2 transfer")` 
    

    其結果是nil,因爲println總是返回nil。我不認爲 這就是你想要的。

  3. 你在你的競賽條件transfer函數。由於您沒有修改原子上的fromto,所以有可能在那裏參加比賽。

+0

但是,當我在事務內部調用'transfer'時,它應該是原子的,不是嗎? – lapots

+0

嗯,我只是想顯示消息。有沒有辦法避免顯示狀態? – lapots

+0

>但是,當我調用內部交易時,它應該是原子的,不是嗎? 是的,這是正確的。但是,「轉讓」的正確性取決於它是如何被調用的,這不是一個好的財產。 說實話,我並不真正瞭解你的代碼的全部目的。你究竟想要打印什麼? – fernandohur