【问题标题】:Race condition in Clojure stm?Clojure stm中的竞争条件?
【发布时间】:2015-02-01 11:51:23
【问题描述】:
您好,我正在阅读 clojure 的书,在关于 STM 的部分中,他们有 2 个事务的图像,其中 A 最初从 ref 中检索与 B 相同的值,然后事务 A 和 B 都进行计算但是 A 先完成并提交到变量,因此 B 必须重试。
但我正在思考的是,如果 B 会用 A 的提交重试。如果是这样的话,如果情况相反呢?那么最终的值就会有很大的不同。
这似乎是一个被忽视的简单危险,我相信我并不完全理解它。请帮我解开这个问题。
【问题讨论】:
标签:
clojure
race-condition
stm
【解决方案1】:
我们来看例子:
(defn test-trans []
(let [x (ref 1)
t-inc #(dosync (alter x inc))
t-mul #(dosync (alter x (partial * 2)))
fns (flatten (repeat 10 [t-mul t-inc]))]
(last (pmap (fn [f] (f)) fns))
@x))
这里我们有 2 个事务函数 - 将 x 加 1 并将 x 乘以 2。我们并行应用 20 个此类函数(每种 10 个)并观察 ref 的最终值。事实上,每次运行的结果都不同:
=> (test-trans)
2418
=> (test-trans)
2380
=> (test-trans)
1804
=> (test-trans)
4210
其实这是正确的行为。 STM 保证代码将在没有锁的情况下执行,并且以原子方式应用更改(它们不能仅部分应用)。但是,它不能保证我们在不同的交易顺序下会有相同的结果。
Clojure 提供了出色的并行编程工具,大大简化了正确代码的编写。但是避免这种竞争条件是开发人员的责任(事实上,这种情况是糟糕的系统设计的明显迹象)。
另一个来自 SQL 的例子:
DELETE FROM tbl WHERE col=1
UPDATE tbl SET col=2 WHERE col=1
如果这些查询是并行执行的,那么无论事务使用什么隔离级别 - 结果都将取决于顺序。