未来内部的 Clojure dosync 与 dosync 内部的未来

Clojure dosync inside future vs future inside dosync

我有如下一段代码

(def number (ref 0))

(dosync (future (alter number inc)))  ; A
(future (dosync (alter number inc)))  ; B

第二个成功,但第一个失败 no transaction is running。但它被包裹在一个 dosync 中,对吗?

clojure 是否记得根据创建它的线程打开事务?

你是对的。 dosync 的全部目的是在当前线程中开始一个事务。 future 在新线程中运行其代码,因此 alter 以防 A 不在其线程的 dosync 内。

对于情况 B,alterdosync 都在同一个(新)线程中,所以没有问题。

这不起作用的原因有多种。正如艾伦·汤普森 (Alan Thompson) 所写,事务归属于单个线程,因此当您创建新线程时,您会丢失事务。

另一个问题是 dosync 的动态范围。如果你写

也会出现同样的问题
((dosync #(alter number inc)))

这里我们在 dosync 范围内创建一个函数,并让该函数成为 dosync 的结果。然后我们从dosync块外调用函数,当然交易不再是运行.

这与您使用 future 所做的非常相似:future 创建一个函数,然后在新线程上执行它,返回一个句柄,您可以使用它来检查该函数的进度线。即使允许跨线程事务,这里也会出现竞争条件:dosync 块是在执行 future 中的 alter 调用之前还是之后关闭其事务?