(def a (ref 0))
(def b (ref 0))
(def f1 (future
(dosync
(println "f1 start")
(alter a inc)
(Thread/sleep 500)
(alter b inc)
(println "f1 end"))))
(def f2 (future
(dosync
(println "f2 start")
(alter a inc)
(println "f2 end"))))
@f1 @f2
在上面的示例中,我认为线程f2应该在f1之前终止,尽管f1在f2之前到达表达式(alter ),但是f1继续其耗时的执行,因此f2首先提交了,因此,在f1委托时,它创建了ref已被修改,然后f1应该重新尝试。但结果表明我错了,它打印了以下内容:
f1 start
f2 start
f2 start
f2 start
f2 start
f2 start
f1 end
f2 start
f2 end
重新尝试的似乎是f2,f1似乎“锁定”了裁判(alter ),f2等待f1“释放锁”,f2才能成功地提交修改。根本的机制是什么?
发布于 2017-12-23 02:13:53
您的程序说明了STM的一个问题:当多个事务在同一状态下工作时,这些事务本质上必须是可串行化的,这是串行运行的(一个接一个完整地运行)。
这就是为什么长时间运行的事务确实是一件非常糟糕的事情,因为它们可能会导致所有在同一裁判上工作的其他事务都重试,即使理论上它们可以很快完成。
commute
是用来缓解这个问题的工具。如果您知道不同事务中的某些操作会更改相同的引用,但由于它们是可交换操作,因此不会(在逻辑上)相互干扰,那么您可以使用commute
而不是alter
来放松可串行化的要求。
是的,STM事务内部使用锁。基本上,您可以将(alter a inc)
看作是获得ref a
上的“写锁”,如果它已经被接受,则失败并重新尝试--请考虑这是一个实现细节。(有复杂的情况:在压力下,旧事务可以突破年轻事务所持有的锁;此外,STM在内部使用超时,因此在程序中使用超时会使这些实现细节浮出水面。)
发布于 2017-12-23 12:23:27
这似乎取决于时间的不同。我试过你的版本得到了同样的结果。然后我稍微改变了一下,得到了不同的结果:
(let [a (ref 0)
b (ref 0)
f1 (future
(dosync
(println "f1 start")
(alter a inc)
(Thread/sleep 500)
(alter b inc)
(println "f1 end")))
f2 (future
(dosync
(println "f2 start")
(alter a inc)
(println "f2 end")))]
(println @f1)
(println @f2)
(println @a)
(println @b))
取得的成果:
Testing tst.demo.core
f1 start
f2 start
f2 start
f2 end
f1 start
f1 end
(clojure.core/deref f1) => nil
(clojure.core/deref f2) => nil
(clojure.core/deref a) => 2
(clojure.core/deref b) => 1
因此,在任何特定时间,任何特定机器上的线程的详细计时似乎都有很大的不同。
我会承认,我很惊讶,因为我会预测与你同样的事情。你的结果和这个新的结果都不是我所期望的。
更新
我修改了一下,然后得到了预期的结果:
(let [a (ref 0)
b (ref 0)
f1 (future
(dosync
(println "f1 start")
(alter a inc)
(Thread/sleep 500)
(alter b inc)
(println "f1 end")))
f2 (future
(dosync
(Thread/sleep 100)
(println "f2 start")
(alter a inc)
(println "f2 end")))]
(println @f1)
(println @f2)
(println @a)
(println @b))
f1 start
f2 start
f2 end
f1 start
f1 end
(clojure.core/deref f1) => nil
(clojure.core/deref f2) => nil
(clojure.core/deref a) => 2
(clojure.core/deref b) => 1
https://stackoverflow.com/questions/47950020
复制相似问题