【问题标题】:clojure's commute example from the docs produces duplicates文档中的 clojure 通勤示例产生重复项
【发布时间】:2018-02-13 06:51:22
【问题描述】:

此设置与此处的文档直接 不同: https://clojuredocs.org/clojure.core/commute

我将使用我的 cmets 照原样复制代码:

(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 毫秒,如示例中所示:

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

这绝对不是文档中承诺的结果!运行时间的差异如宣传的那样,但是重复项呢?我很容易出现拼写错误,所以我从头开始重新做 - 同样的问题。

【问题讨论】:

    标签: concurrency clojure


    【解决方案1】:

    “commute 返回 ref 的新值。 但是,由于重新排序,您在通勤中看到的最后一个事务中值并不总是与 ref 的事务结束值匹配。如果另一个事务潜入并更改了您尝试通勤的 ref,则 STM 不会重新启动您的事务。相反,它将简单地再次运行您的通勤功能,无序。您的交易甚至永远不会看到您的通勤函数最终运行的 ref 值。”

    由于 Clojure 的 STM 可以在您背后重新安排通勤,您可以使用 仅当您不关心订购时才使用它们。”

    摘自:Stuart Halloway。 “编程 Clojure。”

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

    【讨论】:

    • 乱序不让我担心。最大的担忧是我观察到的结果与文档中的结果大不相同。不仅重新排序 - 重复。示例中没有这些。
    • @alexakarpov 请记住,在并发的情况下,结果可能因机器而异。您从 clojuredocs 复制的示例是由某个随机用户提交的,代表他本地机器的输出。正如 Stuart Halloway 所提到的 - commute 返回的值与交易后 ref 的实际状态无关,即它非常随机,你不应该依赖它。
    • 如果我们明确说明您的dosync 的返回值是什么,也许会更清楚。 dosync 返回在其中计算的最后一个表达式的结果,在本例中是您的 commute 调用。当然,这个commute 可能会多次返回相同的值:这正是您所要求的!完成的每个事务都会向您的 ref 提交一个独特的、一致的值,但这仍然无法及时返回并更改 commute 返回的内容,也无法更改 dosync 返回的内容。
    猜你喜欢
    • 1970-01-01
    • 2018-04-29
    • 1970-01-01
    • 1970-01-01
    • 2021-07-03
    • 2023-02-04
    • 2021-09-28
    • 1970-01-01
    • 2014-03-06
    相关资源
    最近更新 更多