【问题标题】:Can the alter be replaced with commute in the following Clojure code?在以下 Clojure 代码中,alter 可以替换为 commute 吗?
【发布时间】:2019-11-20 13:21:38
【问题描述】:
(def alice-height
  (ref 3))

(def right-hand-bites
  (ref 10))

(defn eat-from-right-hand []
  (dosync
    (when (pos? @right-hand-bites)
      (alter right-hand-bites dec)
      (alter alice-height #(+ % 24)))))

此代码来自 Living Clojure 一书。书中作者还举了一个例子,将alter替换为commute。我想知道一开始的pos? 测试,我们真的可以做这个替换吗?

【问题讨论】:

    标签: concurrency clojure


    【解决方案1】:

    不,当递减 right-hand-bites 时将 alter 替换为 commute 不正确。

    条件的意图显然是为了防止right-hand-bites 变成否定的。只有在right-hand-bites 在事务结束之前不会改变的假设下,减量才有效。虽然与alter 一样,commute 拥有自己的 ref 世界快照视图,但它会在 提交时重新读取和重新应用 commute 函数到 ref,那就是这个程序有一个错误。

    因此,使用commute 可以将负值提交给right-hand-bites

    要么坚持使用alter,要么使用ensure 而不是@(尽管这会使整个通勤练习变得毫无意义)。

    【讨论】:

    • 一个有趣的小事实:ensure 不仅在这里不重要,它还容易发生(灾难性)活锁,我实际上可以使用您的代码 sn-p 轻松重现这一点。见CLJ-2301
    • 我认为这是否重要归结为条件(when (pos? @right-hand-bites) ...)中的读取。 right-hand-bites 上的 deref notcommute 内,并且在提交之前应该遵守快照一致性。因此,如果条件在读取过程中看到一个正的right-hand-bites,那么在提交之前应该保证它的值是一致的。如果条件在通勤范围内,这将改变。
    • @A.Webb Ref 读取无法在提交时检测到修改 - 为此您需要 ensure。这又是问题的症结所在:commute 在提交期间(=仍在事务内部)重新读取 ref 的 current value(快照之外的那个!),然后重新应用通勤功能无条件。这就是它成为一个检查然后行动的错误的地方。在 REPL 中自己尝试一下,验证起来并不难。
    猜你喜欢
    • 1970-01-01
    • 2011-05-31
    • 2011-10-21
    • 2017-07-07
    • 1970-01-01
    • 2011-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多