Como as chamadas do Dosync aninhadas se comportam?
Pergunta
O que acontece quando você cria chamadas do Dosync aninhadas? As sub-transações serão concluídas no escopo dos pais? Essas sub-transações são reversíveis se a transação pai falhar?
Solução
Se você quer dizer ninho sintático, a resposta é depende se o interno dosync
vai correr no mesmo fio que o externo.
Em Clojure, sempre que um dosync
O bloco é inserido, uma nova transação é iniciada Se alguém ainda não está funcionando neste tópico. Isso significa que, enquanto a execução permanece em um único encadeamento, pode -se dizer que as transações internas são incluídas por transações externas; No entanto, se a dosync
ocupa uma posição sintaticamente aninhada dentro de outro dosync
, mas por acaso foi lançado em um novo thread, ele terá uma nova transação para si mesma.
Um exemplo que (espero) ilustra o que acontece:
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
A transação "interna" experimenta após a impressão :foo
; A transação "externa" nunca precisa reiniciar. (Observe que depois disso acontece, r
A cadeia de história é cultivada, então se o "grande" dosync
a forma foi avaliada pela segunda vez, o interno dosync
não tentaria novamente. Ainda não seria fundido no exterior, é claro.)
Aliás, Mark Volkmann escreveu um artigo fantástico sobre Clojure's Memória transacional de software; É uma leitura altamente recomendada para qualquer pessoa interessada em obter uma visão sólida de detalhes desse tipo.