2010-05-15 9 views

Respuesta

15

Si se refiere a la anidación sintáctica, entonces la respuesta es que depende de si el interior dosync se ejecutará en el mismo hilo como el exterior de uno.

En Clojure, cada vez que se ingresa un bloque dosync, se inicia una nueva transacción si no se ha ejecutado uno ya en este hilo. Esto significa que mientras la ejecución se mantiene en un solo hilo, puede decirse que las transacciones internas están subsumidas por las transacciones externas; sin embargo, si un dosync ocupa una posición sintácticamente anidada dentro de otro dosync, pero sucede que se lanzará en un nuevo hilo, tendrá una nueva transacción para sí mismo.

Un ejemplo que (esperemos) ilustra lo que sucede:

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 

La transacción "interior" reintenta después de la impresión :foo; la transacción "externa" nunca necesita reiniciarse. (Tenga en cuenta que después de que esto suceda, la cadena de historial de r crece, por lo que si se evalúa la forma "grande" dosync por segunda vez, la dosync interna no se volvería a intentar. Todavía no se fusionaría con la externa, por supuesto)

Por cierto, Mark Volkmann ha escrito un artículo fantástico sobre Clojure's Software Transactional Memory; es una lectura muy recomendable para cualquier persona interesada en obtener una visión sólida de los detalles de este tipo.

+0

Me gusta este ejemplo. –

+0

¿Por qué el calificador "sintácticamente"? ¿Y qué significa sintácticamente? Soy un celador común y estoy acostumbrado a "léxicamente", como al cerrar las variables que son léxicamente visibles: (let ((x 42)) (lambda() x)) vs dynamically (es decir, encuadernado en la pila de llamadas en alguna parte) – kennytilton

Cuestiones relacionadas