gpt4 book ai didi

clojure - 多个引用文献的一致读取

转载 作者:行者123 更新时间:2023-12-03 00:23:05 25 4
gpt4 key购买 nike

我想知道是否只能在事务内获得一致的读取。下面是一些代码来说明问题:

(def foo (ref 0))     
(def bar (ref 0))
(defn incer [] (dosync (alter foo inc) (alter bar inc)))
(.start (Thread. (fn [] (last (repeatedly incer))))) ;; create a lot of action

现在我想打印 foo 和 bar 的值

(println @foo @bar)
;=> 328498765 328498766

我知道我可以使用 Ensure 获得一致的值

(dosync (ensure foo) (ensure bar) (println @foo  @bar))
;=> 356117587 356117587

我想知道这是唯一的方法还是有更好的解决方案。在他的演讲中“我们到了吗?” ( http://www.infoq.com/presentations/Are-We-There-Yet-Rich-Hickey )在第 55 分钟,Rich 展示了一张幻灯片,暗示有一些方法可以在不将感知放入交易中的情况下做到这一点,但我不知道如何做。

最佳答案

您确实需要事务来获得一致的读取,但不需要确保:

;; will print consistent values
(dosync (println @foo @bar))

事务中的引用读取操作就像针对整个系统状态的快照执行的一样。如果无法获得这种意义上一致的值,则重试事务。有一个历史机制,它存储每个 Ref 的许多先前值 - 每个 Ref 的具体数量是可配置的(参见 (doc ref)),默认值是每个Ref 一开始根本不存储任何历史记录,每次参与失败的快照场景时,它都会添加一个新条目,最多可达 10 个。

ensure 的目的是防止写入倾斜,同时允许比 (ref-set some-ref @some-ref) 更多的并发性。要了解写入倾斜,请参阅 Wikipedia 页面 Snapshot isolation 。简而言之,当两个或多个事务读取重叠的 Refs 集并写入非重叠的 Refs 集时,可能会发生异常:

(def foo (ref 0))
(def bar (ref 0))

;; timeouts added to the transaction bodies
;; to make the demonstration reliable:

(future (dosync
(let [f @foo
b @bar]
(Thread/sleep 1000)
(if (zero? (+ f b))
(alter foo dec)))))

(future (dosync
(let [f @foo
b @bar]
(Thread/sleep 1000)
(if (zero? (+ f b))
(alter bar dec)))))

(println @foo @bar)

在这里,两个事务都可以在任一事务提交之前读取两个 Ref,并愉快地继续递减两个 Ref 的值,而显然,事务的任何串行执行只会递减一个值。将 @bar 更改为 (ensure bar) 并将 @foo 更改为 (ensure foo) 将排除这种情况。

(实际上(ensure bar)只在不修改bar的交易中需要,(ensure foo)只在不修改bar的交易中需要不修改foo的事务。在ensure有用的场景中,它可以用来代替deref/@,因为 (ensure foo) 返回 foo 的事务中值。)

关于clojure - 多个引用文献的一致读取,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20069018/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com