2010-08-27 14 views
10

¿Cuál es la diferencia entre el enfoque Clojure STM (dosync) y el bloque de sincronización de Java?Clojure STM (dosync) x bloque de sincronización de Java

Estoy leyendo el código a continuación del problema "El peluquero durmiente". (http://www.bestinclass.dk/index.clj/2009/09/scala-vs-clojure-round-2-concurrency.html)

(defn the-shop [a] 
    (print "[k] entering shop" a) 
    (dosync  
    (if (< (count @queue) seats) 
     (alter queue conj a) 
     (print "[s] turning away customer" a)))) 

Para evitar las condiciones de carrera, se utiliza dosync, por lo que me pregunto: "¿Cuál es la diferencia (STM) desde Java sincronizar bloque"? ¿Bloqueará este código crítico?

¡Gracias de antemano! Dantas

+0

De nada. :-) –

+0

Hola, Michl, como me respondiste perfectamente sobre STM, déjame preguntarte otras cosas sobre clojure de las que no me doy cuenta. La forma de Conmutar. Supongamos que tengo 2 hilos (t1 y t2). Y la ideia es incrementar una referencia, ¿de acuerdo? t1 dentro de una dosincronización, obtenga el valor de referencia - en el valor de transacción (0) - ... t2 obtenga el control y pueda incrementar la referencia de 0 a 1. t1 vuelva, y ¿qué se supone que debe hacer? Si t1 continúa ejecutando el resultado final, no será correcto. ¿Cómo funciona el viaje al trabajo en este caso? gracias de antemano – CHAPa

Respuesta

19

y dan acceso a abstracciones de simultaneidad completamente diferentes.

synchronized es una forma de adquirir y liberar cerraduras. Cuando un hilo entra en un bloque synchronized, intenta adquirir el bloqueo apropiado; si el bloqueo está retenido actualmente por un hilo diferente, el hilo actual bloquea y espera a que se libere. Esto conduce a ciertos problemas, como el riesgo de interbloqueo. El bloqueo se libera cuando el hilo sale del bloque synchronized.

dosync marca un bloque de código que se ejecutará en una transacción. Las transacciones en Clojure son una forma de coordinar los cambios en Refs (objetos creados con la función ref); si necesita un código para tener una vista coherente de algunas piezas de estado mutable en Clojure, y posiblemente cambiarlas, las pone en Refs y ejecuta su código en una transacción.

Una transacción tiene la interesante propiedad de que se reiniciará si por alguna razón no puede confirmarse, hasta un cierto número máximo de intentos (actualmente codificados como 10000). Entre los posibles motivos por los que una transacción no puede comprometerse se encuentra la imposibilidad de obtener una visión coherente del mundo (en realidad, las referencias pertinentes - existe una función de "historia adaptativa" que hace que este problema no sea tan grande como podría parecer a la primera vista); cambios simultáneos realizados por otras transacciones; etc.

Una transacción no corre el riesgo de quedar estancada (a menos que el programador se desvíe de su camino para introducir un interbloqueo no relacionado con el sistema STM a través de la interoperabilidad Java); Livelock, por otro lado, es una cierta posibilidad, aunque no es muy probable. En general, muchos, ¡aunque no todos! - de las intuiciones que los programadores asociados con las transacciones de bases de datos son válidas en el contexto de los sistemas STM, incluido el de Clojure.

STM es un gran tema; Un recurso excelente para aprender sobre el STM de Clojure es el artículo de Mark Volkmann, Software Transactional Memory. Se profundiza en la discusión del STM de Clojure en sus secciones finales, pero el comienzo puede ser una gran lectura introductoria.

En cuanto al fragmento que citó, en realidad no es algo que normalmente desee emular en el código de producción, ya que los bloques dosync casi siempre deberían tener efectos secundarios libres; El print aquí puede ser útil para demostrar el funcionamiento interno del STM, pero si desea que una transacción cause efectos colaterales en el código real, debe hacer que genere un agente Clojure para ese fin (que solo ejecutaría su tarea si el la transacción se compromete con éxito).

+0

Michal, usted escribió "ya que los bloques dosync casi siempre deberían tener efectos secundarios libres". ¿una impresión de consola romperá esta propiedad de "efecto secundario"? así que actualizar una tabla de base de datos hará lo mismo, ¿está bien? ¿Qué se supone que debe estar dentro de un bloque dosync? Gracias de nuevo, excelente publicación! – CHAPa

+2

A la derecha, imprimiendo en la consola y actualizando una tabla de base de datos ambos califican como efectos secundarios. 'los bloques' dosync' en general no se supone que contengan código de efecto secundario * excepto * llamadas a funciones de modificación de Ref consciente de la transacción ('alter' /' conmutar'/'ref-set'), con la importante excepción de que cualquier acción enviado a los Agentes puede contener efectos secundarios que suceden después de que se complete la transacción (todas esas acciones se realizarán si y cuando la transacción se compromete, por lo que no hay riesgo de causar el mismo efecto secundario más de una vez). –

+1

Por lo tanto, si necesita modificar los valores de un par de Refs y actualizar su base de datos, su 'dosync' contendría llamadas' alter'/'conmuta' para cambiar los Refs y un mensaje' send'/'send-off' un agente para realizar la actualización de db una vez que la transacción se haya comprometido (y por lo tanto ya no corre el riesgo de reintentar o fallar debido al límite de reintento alcanzado). –

3

Además de la excelente respuesta de Michał, con las transacciones de STM, lee siempre obtiene el valor congelado al comienzo de la transacción y no necesita esperar a que se complete ninguna transacción en curso.

+0

¡Sí! Las operaciones de lectura no requieren bloqueo. está libre de cerradura. cuando lees, obtienes una instantánea. Pero si escribe, la operación solo confirma si la instantánea es igual a la que tiene. si cuando intenta escribir los datos no son los mismos, la operación de reversión. – CHAPa

3

Sólo para dar una imagen completa para aquellos que buscan, Clojure tiene un synchronized analógico. Es útil cuando uno tiene que trabajar con tipos de Java que no son seguros para la interoperabilidad.

(locking x & body) 
0

diferencia básica está siguiendo

Clojure STM apoya optimista concurrencia mientras JAVA sincronizada es pesimista

Clojure STM no adquiere de bloqueo hasta que no haya más de un hilo. si el estado mutable se actualiza por otro hilo, se repite la operación dentro de dosync. Además, dosync es obligatorio para estados mutables. Clojure arroja la excepción illegalState cuando falta la sincronización, a diferencia de JAVA.

Cuestiones relacionadas