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