clojure sendoff 打印函数

clojure sendoff println function

我正在尝试 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 消息。有什么问题?

您使用 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. 你的 transfer 函数

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

    看起来你真的想说 alter from 然后 alter to

  2. 来自 send-off 文档:

    Dispatch a potentially blocking action to an agent. Returns the agent immediately. Subsequently, in a separate thread, the state of the agent will be set to the value of: (apply action-fn state-of-agent args)

    所以我认为你不需要那个未来。还有行

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

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

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

    nil,因为 println 总是 returns nil。我不认为 这就是你想要的。

  3. 您的 transfer 函数中存在竞争条件。由于您没有以原子方式修改 fromto,因此那里有可能发生竞争。