clojure sendoff println功能

时间:2017-03-20 19:13:10

标签: clojure stm

我在交易中尝试send-off函数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条消息。有什么问题?

2 个答案:

答案 0 :(得分: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立即运行。我们在调用shutdown-agents之前等待2000毫秒,这会杀死阻止代理运行的所有代理线程。

答案 1 :(得分: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文档:

      

    向代理发送可能阻止的操作。返回代理   立即。随后,在一个单独的线程中,状态   agent将设置为以下值:(应用action-fn state-of-agent   参数)

    所以我认为你不需要那个未来。这一行

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

    表示您将代理的状态设置为

    的结果
    (println state-of-agent "T2 transfer")`
    

    nil,因为println始终返回nil。我不认为 这就是你想要的。

  3. transfer函数中存在竞争条件。由于您没有原子地修改fromto,因此可能会在那里进行比赛。