online - clojurescript
¿Qué es Clojure volátil? (2)
El nuevo volátil es tan cercano como una "variable" real (como lo es de muchos otros lenguajes de programación) como lo es para clojure.
Del anuncio :
hay un nuevo conjunto de funciones (
volatile!
vswap!
vreset!
volatile?
) para crear y usar "cajas" volátiles para mantener el estado en transductores con estado. Los volátiles son más rápidos que los átomos pero renuncian a las garantías de atomicidad, por lo que solo deben usarse con aislamiento de hilos.
Por ejemplo, puede establecer / obtener y actualizar como lo haría con una variable en C. La única adición (y, por tanto, el nombre) es la palabra clave volatile
para el objeto java real .
Esto es para evitar que la JVM se optimice y se asegura de que lea la ubicación de la memoria cada vez que se acceda a ella. De dev.clojure.org/jira/browse/CLJ-1512 :
Clojure necesita una variante más rápida de Atom para administrar los transductores internos del estado. Es decir, los átomos hacen el trabajo, pero proporcionan demasiada capacidad para los transductores. Específicamente, la semántica de comparación y intercambio de Átomos agrega demasiada sobrecarga. Por lo tanto, se determinó que un tipo de ref simple volátil funcionaría para asegurar la propagación básica de su valor a otros hilos y lecturas de la última escritura de cualquier otro hilo. Si bien las actualizaciones están sujetas a condiciones de carrera, el acceso está controlado por las garantías de JVM.
Descripción general de la solución: cree un tipo concreto en Java, similar a clojure.lang.Box, pero el interior volátil admite IDeref, pero no relojes, etc.
¡Esto significa, un volatile!
aún se puede acceder mediante varios subprocesos (que es necesario para los transductores) pero no permite que estos subprocesos los modifiquen al mismo tiempo, ya que no ofrece actualizaciones atómicas.
La semántica de lo que hace volatile
está muy bien explicada en una respuesta de Java :
Hay dos aspectos para la seguridad del hilo: (1) control de ejecución y (2) visibilidad de la memoria. El primero tiene que ver con controlar cuándo se ejecuta el código (incluido el orden en que se ejecutan las instrucciones) y si se puede ejecutar simultáneamente, y el segundo con cuándo los efectos en la memoria de lo que se ha hecho son visibles para otros hilos. Debido a que cada CPU tiene varios niveles de caché entre ella y la memoria principal, los hilos que se ejecutan en diferentes CPU o núcleos pueden ver la "memoria" de forma diferente en un momento dado porque los subprocesos pueden obtener y trabajar en copias privadas de la memoria principal.
Ahora veamos por qué no usar var-set
o transients
:
Volatile vs var-set
Rich Hickey no quería dar variables verdaderamente mutables :
Sin locales mutables, las personas se ven obligadas a recurrir, una construcción de bucle funcional. Si bien esto puede parecer extraño al principio, es tan breve como bucles con mutación, y los patrones resultantes se pueden reutilizar en cualquier otro lugar en Clojure, es decir, recurrir, reducir, alterar, conmutar, etc., son todos (lógicamente) muy similares. [...] En cualquier caso, los Vars están disponibles para su uso cuando corresponda.
Y creando así with-local-vars
, var-set
etc. El problema con estos es que son verdaderos vars y la cadena de documentación de var-set
te dice:
La var debe estar enlazado localmente.
Esto es, por supuesto, no una opción para core.async que potencialmente se ejecuta en diferentes subprocesos. También son mucho más lentos porque hacen todos esos controles.
Por qué no usar transitorios
Transients son similares en cuanto a que no permiten el acceso simultáneo y optimizan la mutación de una estructura de datos. El problema es que los transitorios solo funcionan con colecciones que implementan IEditableCollection
. Es decir, simplemente evitan la costosa representación intermedia de las estructuras de datos de la colección. También recuerde que los transitorios no se ajustan a su lugar y aún necesita alguna ubicación de memoria para almacenar el transitorio real. Los compuestos volátiles a menudo se usan simplemente para mantener una bandera o el valor del último elemento (ver partition-by
por ejemplo)
Resumen:
Los volátiles no son más que un envoltorio alrededor de la volatilidad de Java y tienen exactamente la misma semántica. Nunca los compartas. Úselos solo con mucho cuidado.
Ha habido una adición en la reciente versión de Clojure 1.7: volatile!
volatile
ya se usa en muchos idiomas, incluido Java, pero ¿cuál es la semántica en Clojure?
¿Qué hace? ¿Cuándo es útil?
Los volátiles son un "átomo más rápido" sin garantías de atomicidad. Se introdujeron porque los átomos se consideraban demasiado lentos para mantener el estado en los transductores.
hay un nuevo conjunto de funciones (
volatile!
vswap!
vreset!
volatile?
) para crear y usar "cajas" volátiles para mantener el estado en transductores con estado. Los volátiles son más rápidos que los átomos, pero renuncian a las garantías de atomicidad, por lo que solo deben usarse con aislamiento de hilos