Clojure 嵌套的dosync调用的行为如何?

Clojure 嵌套的dosync调用的行为如何?,clojure,stm,Clojure,Stm,创建嵌套的dosync调用时会发生什么?子交易是否在父范围内完成?如果父事务失败,这些子事务是否可逆?如果您指的是语法嵌套,那么答案是这取决于内部dosync是否将在与外部相同的线程上运行 在Clojure中,每当输入dosync块时,如果尚未在此线程上运行新事务,则会启动新事务。这意味着,当执行停留在单个线程上时,可以说内部事务被外部事务所包含;但是,如果一个dosync占据了另一个dosync中语法嵌套的位置,但恰好在一个新线程上启动,那么它自身将有一个新事务 一个(希望)说明发生了什么的例

创建嵌套的dosync调用时会发生什么?子交易是否在父范围内完成?如果父事务失败,这些子事务是否可逆?

如果您指的是语法嵌套,那么答案是这取决于内部
dosync
是否将在与外部相同的线程上运行

在Clojure中,每当输入
dosync
块时,如果尚未在此线程上运行新事务,则会启动新事务。这意味着,当执行停留在单个线程上时,可以说内部事务被外部事务所包含;但是,如果一个
dosync
占据了另一个
dosync
中语法嵌套的位置,但恰好在一个新线程上启动,那么它自身将有一个新事务

一个(希望)说明发生了什么的例子:

user> (def r (ref 0))
#'user/r
user> (dosync (future (dosync (Thread/sleep 50) (println :foo) (alter r inc)))
              (println :bar)
              (alter r inc))
:bar
:foo
:foo
1
user> @r
2
“内部”事务在打印后重试
:foo
;“外部”事务永远不需要重新启动。(请注意,在这种情况发生后,
r
的历史链将增长,因此,如果第二次评估“大”的
dosync
表单,内部的
dosync
将不会重试。当然,它仍然不会合并到外部的。)

顺便说一句,马克·沃克曼写了一篇关于Clojure的精彩文章;对于任何有兴趣深入了解此类细节的人,强烈建议阅读本书。

为什么要使用“语法”限定符?那么,从句法上来说,这意味着什么呢?我是一个普通的lisper,我习惯于“词汇化”,比如在词汇上可见的变量上关闭:(let((x 42))(lambda()x))vs动态(即,绑定在调用堆栈的某个地方)。