2017-03-20 4 views
1

send-offファンクションprintln取引中です。クロージャー送り出し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を1回だけ実行することにしました。

しかし、私はこの

(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) 
) 

:T1はすぐに実行されている間

: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ミリ秒を待ちます。 shutdown-agentsを呼び出す前に2000ミリ秒待つと、すべてのエージェントスレッドが終了してエージェントが実行されなくなります。

+0

ああ、私はそれを得る。基本的に 'println transfer'を呼び出す前に私は10秒待っています(トランザクションは再試行されました)が、コミットされるまでにエージェントはシャットダウンされます – lapots

1

私はあなたのコードの断片と間違っている少なくとも三つのことを参照してください。あなたが実際にfromを変更して、変更言いたいように見えます

  1. あなたtransfer機能

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

    to

  2. send-offからdocs:

    潜在的なブロックアクションをエージェントにディスパッチします。すぐにエージェント を返します。その後、別のスレッドで、 エージェントの状態がの値に設定されます(アクション-FN最先端のエージェント 引数を適用)

    だから私は、あなたがその将来を必要としないと思います。また、ライン

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

    あなたはprintlnは常にnilを返すことから、nilある

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

    の結果に、エージェントの状態を設定していることを意味します。私はあなたが欲しいものだとは思わない。

  3. あなたの競合状態はtransferです。 fromtoを原子的に変更していないので、そこに競争の可能性があります。

+0

しかしトランザクション内で' transfer'を呼び出すと、 – lapots

+0

さて、メッセージを表示したいだけです。状態を表示しないようにする方法はありますか? – lapots

+0

>しかし、私はトランザクション内で転送を呼び出すので、それはどんな場合でもアトミックでなければなりません、いいえ? はい、正しいです。しかし、 'transfer'の正しさは、それが呼び出される方法に依存しますが、これは素敵なものではありません。 正直言って私はあなたのコードの目的を完全に理解していません。あなたは正確に何を印刷しようとしていますか? – fernandohur

関連する問題