“Clojure 编程”(Emerick,O'Reilly)指出:
(...) 如果自当前事务开始后由另一个事务提交了新值,则无法提供截至事务开始时的新值。有用的是,STM 注意到了这个问题,并维护了事务中涉及的 refs 状态的有限历史,其中历史的大小随着每次重试而增加。这增加了 - 在某些时候 - 事务不必再重试的机会,因为虽然 ref 被同时更新,但所需的值仍然存在于历史记录中。
接下来,他们给出了一些代码示例来说明问题。
首先,为了说明读取事务只有在所有写入事务完成后才会成功(因此a = 500
):
(def a (ref 0))
(future (dotimes [_ 500] (dosync (Thread/sleep 20) (alter a inc))))
@(future (dosync (Thread/sleep 1000) @a))
; 500
(ref-history-count a)
; 10
其次,为了说明该设置:min-history
并:max-history
有助于读取器事务重试(这次a
已成功读取较早 - 值为 33):
(def a (ref 0 :min-history 50 :max-history :100))
(future (dotimes [_ 500] (dosync (Thread/sleep 20) (alter a inc))))
@(future (dosync (Thread/sleep 1000) @a))
; 33
我确实理解为什么deref
读取器事务内部会导致它重试(当某些写入器事务正在提交对 ref 的更改时)。我不明白的是这部分:“这增加了 - 在某些时候 - 事务不必再重试的机会,因为虽然 ref 被同时更新,但所需的值仍然存在于历史记录中”。
什么是“期望值”?在上面的示例中,参考历史如何随时间变化?有人可以向我指出一个解释或一些带有时间线的例子,显示参考历史是如何工作的吗?