Если вы имеете в виду синтаксическое вложение, то ответ будет , это зависит от того, будет ли внутренний 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 ; Настоятельно рекомендуется прочитать для всех, кто заинтересован в том, чтобы получить полное представление о таких деталях.