Diferencias de Clojure entre Ref, Var, Agent, Atom, con ejemplos

110

Soy muy nuevo en Clojure, ¿pueden darme una explicación con escenarios del mundo real? Quiero decir, dónde usar Ref, Var, Agent, Atom. Leí un libro, pero todavía no podía entender los ejemplos del mundo real.

Miguel
fuente

Respuestas:

174

Recomiendo encarecidamente "The Joy of Clojure" o "programar Clojure" para obtener una respuesta real a esta pregunta, puedo reproducir un breve fragmento de las motivaciones de cada uno:

Comience viendo este video sobre la noción de Identidad y / o estudie aquí .

  • Las referencias son para el acceso sincronizado coordinado a "muchas identidades".
  • Los átomos son para el acceso sincrónico descoordinado a una sola identidad.
  • Los agentes son para el acceso asincrónico no coordinado a una sola identidad.
  • Las variables son para identidades aisladas locales de subprocesos con un valor predeterminado compartido.

El acceso coordinado se usa cuando dos Identidades deben cambiar juntas, el ejemplo clásico es mover dinero de una cuenta bancaria a otra, debe moverse completamente o no moverse en absoluto.

El acceso descoordinado se usa cuando solo se necesita actualizar una identidad, este es un caso muy común.

El acceso sincrónico se utiliza cuando se espera que la llamada espere hasta que todas las identidades se hayan establecido antes de continuar.

El acceso asincrónico es "disparar y olvidar" y dejar que la identidad alcance su nuevo estado en su propio tiempo.

Arthur Ulfeldt
fuente
En el acceso coordinado, si solo quiero cambiar state-a, pero me refiero al state-bhacerlo, todavía necesito un refcorrecto? Entonces, ¿no se trata de cambiar varias cosas, sino de hacer referencia a varias cosas mientras se cambia alguna de ellas?
event_jr
2
Sí, parece que comprende correctamente que el estado-a y el estado-b deben ser ambos refs. Si desea que el nuevo valor en el estado-a se base en una combinación consistente de los valores en ay b. Necesita que ese nuevo valor se haya calculado en un contexto en el que el estado-a y el estado-b sean coherentes entre sí. Cuando ambas son referencias, si b cambia a mitad de camino, la transacción se reiniciará y usará los nuevos valores de ay b. considere usar la ensurefunción: clojure.github.io/clojure/clojure.core-api.html#clojure.core/… para hacer esto explícito y más eficiente.
Arthur Ulfeldt
3
¿Quizás se podría agregar una explicación de lo que Aislado con medios predeterminados compartidos para completar la respuesta?
Didier A.
1
"El acceso coordinado se utiliza cuando es necesario cambiar dos identidades juntas ...". ¿Debería "cambiarse" eso?
Carcigenicate
40

Las referencias son para el estado que debe sincronizarse entre subprocesos. Si necesita realizar un seguimiento de un montón de cosas diferentes y, a veces, necesitará realizar operaciones que escriban en varias de las cosas a la vez, use refs. Siempre que tenga varios estados diferentes, usar referencias no es una mala idea.

Los átomos son para un estado independiente que debe sincronizarse entre subprocesos. Si nunca necesitará cambiar el estado del átomo y cualquier otra cosa al mismo tiempo, usar at atom es seguro (en particular, si solo hay una parte del estado en todo el programa, puede ponerlo en un átomo) . Como ejemplo no trivial, si está tratando de almacenar en caché los valores de retorno de una función (es decir, memorizarla), usar un átomo probablemente sea seguro: el estado es invisible para todo lo que está fuera de la función, por lo que no debe preocuparse sobre un cambio de estado dentro de la función que estropea algo.

El punto principal de los agentes es que se ejecutan en un hilo diferente. Puede obtener el valor del agente y decirle que aplique una función a su valor, pero no sabe cuándo se ejecutará la función ni a qué valor se aplicará la función.

Los Vars son para cuando necesita almacenar algo por hilo. Si tiene un programa de subprocesos múltiples y cada subproceso necesita su propio estado privado, ponga ese estado en una var.

En lo que respecta a los ejemplos del mundo real, si proporciona un ejemplo de lo que está intentando hacer, podemos decirle qué utilizar.

Retief
fuente
32

Cuando leí por primera vez sobre estos tipos, también me costó entender dónde podría o debería usar cada uno, así que aquí está mi respuesta en inglés simple:

Utilice una var cuando los datos no cambien. Esto sucede siempre que usa defo la mayoría de las funciones que comienzan con deflike defn.

Use un átomo cuando tenga un solo elemento que cambie. Un ejemplo podría ser un contador o un vector al que desea agregar elementos.

Utilice una referencia cuando tenga dos o más cosas que deben cambiar al mismo tiempo. Piense en "transacciones de base de datos" si está familiarizado. El ejemplo canónico de esto es transferir dinero de una cuenta a otra. Cada cuenta podría almacenarse en una referencia para que se puedan hacer cambios para que parezcan atómicos.

Utilice un agente cuando desee que algo cambie pero no le importe cuándo. Esto podría ser un cálculo largo o escribir algo en un archivo o socket. Tenga en cuenta que con este último debe usar send-off.

Nota: Aprecio que hay mucho más en cada uno de estos, pero espero que esto le dé un punto de partida.

optevo
fuente
1
Muchas gracias por su respuesta clara :-) Ayuda bastante a un novato de Clojure como yo.
gosukiwi
27

Escribí un artículo con un resumen de la diferencia entre ellos y ayudé a elegir cuándo usar cuál.

Estado compartido: ¿cuándo se usan vars, átomos, agentes y referencias?

Espero que ayude a las personas a buscar respuestas en ese tema.

Algunos atajos del artículo después de la sugerencia de @tunaci:

Vars

Los Vars son globales para todos los hilos.

No cambie vars después de crear. Es técnicamente posible, pero es una mala idea por muchas razones.

Átomos

Comparta el acceso al estado mutable para cada hilo. El cambio ocurre sincrónicamente. Vuelva a intentarlo cuando otro subproceso cambie el estado durante la ejecución.

No utilice funciones no idempotentes y funciones con ejecución prolongada

Agentes

Comparta el acceso al estado mutable para cada hilo. El cambio se produce de forma asincrónica.

Refs

Refs funciona de manera similar a las transacciones de bases de datos. La escritura y la lectura están protegidas en dosync. Puede operar en muchas referencias seguras en la transacción.

Y diagrama de flujo cuando use cuál: diagrama de flujo

Mire la imagen en el sitio web, porque siempre es posible realizar algunas actualizaciones.

Es complejo y un tema largo para dar una respuesta completa sin copia y artículo anterior, así que perdóneme, lo redirecciono al sitio web :)

kabra
fuente