来自文档的clojure通勤示例产生重复

时间:2018-02-13 06:51:22

标签: concurrency clojure

此设置直接超出此处的文档: https://clojuredocs.org/clojure.core/commute

我只是按原样复制代码,并附上我的评论:

(def counter (ref 0))

(defn alter-inc! [counter]
     (dosync (Thread/sleep 100) (alter counter inc)))

(defn commute-inc! [counter]
  (dosync (Thread/sleep 100) (commute counter inc)))

(defn bombard-counter! [n f counter]
  (apply pcalls (repeat n #(f counter))))

(dosync (ref-set counter 0))

使用alter运行会生成随机排序的列表,需要2000 ms,如示例所示:

> (time (doall (bombard-counter! 20 alter-inc! counter)))
"Elapsed time: 2078.859995 msecs"
(7 6 1 5 4 2 3 9 12 10 8 14 11 13 15 18 16 17 20 19)

但是在通勤中运行与官方文档中的声明有很大不同 - 我得到重复:

> (time (doall (bombard-counter! 20 commute-inc! counter)))
"Elapsed time: 309.615195 msecs"
(5 1 1 6 5 4 1 8 8 10 10 12 14 13 15 16 17 18 19 20)

这绝对不是文档中承诺的结果!运行时间的差异与广告一样,但重复的是什么?我很容易发生拼写错误,所以我从头开始重新做 - 同样的问题。

1 个答案:

答案 0 :(得分:0)

  

“commute返回ref的新值。 但是,由于重新排序,您在通勤中看到的最后一个交易中价值并不总是与参考交易结束时的价值相匹配。如果另一个交易悄悄进入并改变您尝试通勤的参考,STM将不会重新启动您的交易。相反,它将简单地再次运行您的通勤功能。您的交易永远不会看到您的通勤功能最终运行的参考值。"

     

由于Clojure的STM可以重新排序你背后​​的通勤,你可以使用   只有当你不关心订购时才会使用它们。“

节选自:Stuart Halloway。 “编程Clojure。”

这就是您在输出中看到无序更新结果的原因。