web-dev-qa-db-fra.com

Clojure différences entre Ref, Var, Agent, Atom, avec des exemples

Je suis très nouveau à Clojure, pouvez-vous me donner des explications avec des scénarios du monde réel. Je veux dire, où utiliser Ref, Var, Agent, Atom. J'ai lu un livre, mais je ne comprenais toujours pas les exemples du monde réel.

103
user472557

Je recommande fortement "The Joy of Clojure" ou "programmer Clojure" pour une vraie réponse à cette question, je peux reproduire un petit snip-it des motivations de chacun:

commencez par regarder cette vidéo sur la notion d'identité et/ou étudier ici .

  • Les références sont pour Synchronisé coordonné accès à "De nombreuses identités".
  • Les atomes sont pour Synchrone non coordonné accès à une seule identité.
  • Les agents sont pour Asynchrone non coordonné accès à une seule identité.
  • Vars sont pour le fil local identités isolées avec une valeur par défaut partagée.

Coordonné l'accès est utilisé lorsque deux identités doivent changer ensemble, l'exemple classique consiste à déplacer de l'argent d'un compte bancaire à un autre, il doit se déplacer complètement ou pas du tout.

Non coordonné l'accès est utilisé lorsqu'une seule identité doit être mise à jour, c'est un cas très courant.

Synchrone l'accès est utilisé lorsque l'appel doit attendre jusqu'à ce que toutes les identités soient réglées avant de continuer.

Asynchrone l'accès est "tirer et oublier" et laisser l'identité atteindre son nouvel état en son temps.

163
Arthur Ulfeldt

Les références sont pour l'état qui doit être synchronisé entre les threads. Si vous devez suivre un tas de choses différentes et que vous devrez parfois effectuer des opérations qui écrivent sur plusieurs choses à la fois, utilisez les références. Chaque fois que vous avez plusieurs états différents, utiliser des références n'est pas une mauvaise idée.

Les atomes sont pour un état indépendant qui doit être synchronisé entre les threads. Si vous n'aurez jamais besoin de changer l'état de atom et toute autre chose en même temps, utiliser à atom est sûr (en particulier, s'il y a un seul état dans tout le programme, vous pouvez le mettre dans un atome). Comme exemple non trivial, si vous essayez de mettre en cache les valeurs de retour d'une fonction (c'est-à-dire la mémoriser), en utilisant un atom est probablement sûr - l'état est invisible pour tout ce qui se trouve en dehors de la fonction, vous n'avez donc pas à vous soucier d'un changement d'état à l'intérieur de la fonction.

Le point principal des agents est qu'ils s'exécutent dans un thread différent. Vous pouvez obtenir la valeur de l'agent et lui dire d'appliquer une fonction à sa valeur, mais vous ne savez pas quand la fonction s'exécutera ni à quelle valeur la fonction sera appliquée.

Vars est pour quand vous avez besoin de stocker quelque chose sur une base par thread. Si vous avez un programme multithread et que chaque thread a besoin de son propre état privé, mettez cet état dans une var.

En ce qui concerne les exemples concrets, si vous fournissez un exemple de ce que vous essayez de faire, nous pouvons vous dire quoi utiliser.

38
Retief

Lorsque j'ai lu pour la première fois sur ces types, j'ai également eu du mal à comprendre où je pouvais ou devrais utiliser chacun d'eux, alors voici ma réponse en anglais:

Utilisez un var lorsque les données ne changeront pas. Cela se produit chaque fois que vous utilisez def ou la plupart des fonctions commençant par def comme defn.

Utilisez un atom lorsque vous avez un seul élément qui change. Un exemple peut être un compteur ou un vecteur auquel vous souhaitez ajouter des éléments.

Utilisez une référence lorsque vous avez deux choses ou plus qui doivent changer en même temps. Pensez aux "transactions de base de données" si vous êtes familier. L'exemple canonique de ceci est le transfert d'argent d'un compte à un autre. Chaque compte pourrait être stocké dans une référence afin que des modifications puissent être apportées pour apparaître atomique.

Utilisez un agent lorsque vous voulez que quelque chose change, mais peu vous importe quand. Cela peut être un long calcul ou écrire quelque chose dans un fichier ou un socket. Notez qu'avec ce dernier, vous devez utiliser send-off.

Remarque: J'apprécie qu'il y a beaucoup plus à chacun d'eux, mais j'espère que cela devrait vous donner un point de départ.

29
optevo

J'ai écrit un article avec un résumé de la différence entre eux et aider à choisir quand utiliser lequel.

Partager l'état - quand utiliser des variables, des atomes, des agents et des références?

J'espère que cela aidera les gens à chercher des réponses dans ce sujet.

Quelques raccourcis de l'article après la suggestion de @tunaci:

Vars

Vars est global pour tous les threads.

Ne changez pas les vars après la création. C'est techniquement possible, mais c'est une mauvaise idée pour de nombreuses raisons.

Atomes

Partagez l'accès à l'état mutable pour chaque thread. Le changement se produit de manière synchrone. Réessayez lorsque l'autre thread change l'état pendant l'exécution.

Ne pas utiliser de fonctions non idempotentes et de fonctions à exécution longue

Agents

Partagez l'accès à l'état mutable pour chaque thread. Le changement se produit de manière asynchrone.

Réfs

Refs fonctionne de manière similaire aux transactions de base de données. L'écriture et la lecture sont protégées dans dosync. Vous pouvez opérer sur de nombreuses références sécurisées en transaction.

Et un organigramme lorsque vous utilisez lequel: flowchart

Veuillez regarder l'image sur le site Web, car certaines mises à jour sont toujours possibles.

Il est complexe et un long sujet de donner une réponse complète sans copie et article précédent, alors pardonnez-moi, je vous redirige vers le site :)

23
kabra

atomes, refs et agents - un certain éclairage ici http://blog.jayfields.com/2011/04/clojure-state-management.html

4
Gokul