Clojure stm 中的竞争条件?
Race condition in Clojure stm?
你好,我正在阅读《joy of clojure》一书,在关于 STM 的部分中,他们有一个 2 个事务的图像,其中 A 最初从 ref 中检索与 B 相同的值,然后事务 A 和 B 都执行他们的计算,但 A 先完成并提交变量,因此 B 必须重试。
但是我在考虑的是 B 是否会重试 A 的提交。如果是这样的话,那么如果相反呢?那么最终的价值就会有很大的不同。
这似乎是一个被忽视的危险,我相信我没有完全理解它。请帮我解开这个问题。
我们来看例子:
(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 个)并观察 [= 的最终值15=]。每个 运行:
的结果确实不同
=> (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
如果这些查询是并行执行的,那么无论事务使用何种隔离级别 - 结果都将取决于顺序。
你好,我正在阅读《joy of clojure》一书,在关于 STM 的部分中,他们有一个 2 个事务的图像,其中 A 最初从 ref 中检索与 B 相同的值,然后事务 A 和 B 都执行他们的计算,但 A 先完成并提交变量,因此 B 必须重试。
但是我在考虑的是 B 是否会重试 A 的提交。如果是这样的话,那么如果相反呢?那么最终的价值就会有很大的不同。
这似乎是一个被忽视的危险,我相信我没有完全理解它。请帮我解开这个问题。
我们来看例子:
(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 个)并观察 [= 的最终值15=]。每个 运行:
=> (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
如果这些查询是并行执行的,那么无论事务使用何种隔离级别 - 结果都将取决于顺序。