Как ведут себя вложенные вызовы dosync? - PullRequest
13 голосов
/ 16 мая 2010

Что происходит, когда вы создаете вложенные вызовы dosync? Будут ли завершены суб-транзакции в родительской области? Являются ли эти подоперации обратимыми в случае сбоя родительской транзакции?

1 Ответ

16 голосов
/ 16 мая 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...