Je suis très novice en matière de Clojure. Pouvez-vous me donner des explications avec des scénarios réels ? Je veux dire, où utiliser Ref, Var, Agent, Atom. J'ai lu le livre, mais je n'ai toujours pas réussi à comprendre les exemples concrets.
Réponses
Trop de publicités?Je recommande vivement "The Joy of Clojure" ou "programming Clojure" pour une vraie réponse à cette question, je peux reproduire un court extrait 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 Coordonné Synchrone l'accès à "Many Identities".
- Les atomes servent à Non coordonné synchrone l'accès à une seule identité.
- Les agents sont pour Asynchrone non coordonné l'accès à une seule identité.
- Les variables sont pour le fil local les 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 étant le transfert d'argent d'un compte bancaire à un autre, il doit être déplacé complètement ou pas du tout.
Non coordonné L'accès est utilisé lorsqu'une seule identité doit être mise à jour, ce qui est un cas très courant.
Synchrone Cet accès est utilisé lorsque l'appel doit attendre 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.
Les références sont pour l'état qui doit être synchronisé entre les threads. Si vous avez besoin de garder la trace d'un tas de choses différentes et que vous aurez parfois besoin de faire des opérations qui écrivent sur plusieurs de ces choses à la fois, utilisez les refs. Chaque fois que vous avez plusieurs éléments d'état différents, l'utilisation des refs n'est pas une mauvaise idée.
Les atomes sont destinés aux états indépendants qui doivent être synchronisés entre les threads. Si vous n'avez jamais besoin de modifier l'état de l'atome et d'autres éléments en même temps, l'utilisation d'un atome est sûre (en particulier, s'il n'y a qu'un seul élément d'é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), l'utilisation d'un atome est probablement sûre - l'état est invisible pour tout ce qui est extérieur à la fonction, donc vous n'avez pas à vous soucier d'un changement d'état à l'intérieur de la fonction qui pourrait tout gâcher.
Le point principal des agents est qu'ils fonctionnent dans un fil différent. Vous pouvez obtenir la valeur de l'agent et lui demander d'appliquer une fonction à sa valeur, mais vous ne savez pas quand la fonction sera exécutée ni à quelle valeur elle sera appliquée.
Les variables sont utilisées lorsque vous avez besoin de stocker quelque chose sur une base individuelle. Si vous avez un programme multithread et que chaque thread a besoin de son propre état privé, mettez cet état dans un 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.
Lorsque j'ai lu pour la première fois ces types de produits, j'ai également eu du mal à comprendre où je pouvais ou devais les utiliser, alors voici ma réponse en langage clair :
Utilisez un var lorsque les données ne changent pas. C'est le cas lorsque vous utilisez def
ou la plupart des fonctions qui commencent par def
comme defn
.
Utilisez un atome lorsque vous avez un seul élément qui change. Il peut s'agir par exemple d'un compteur ou d'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 est le transfert d'argent d'un compte à un autre. Chaque compte pourrait être stocké dans un ref afin que les changements puissent être effectués pour apparaître atomiques.
Utilisez un agent lorsque vous voulez que quelque chose change mais que vous ne voulez pas savoir quand. Cela peut être un long calcul ou l'écriture de quelque chose dans un fichier ou un socket. Notez que dans ce dernier cas, vous devez utiliser send-off
.
Remarque : je suis conscient que chacun de ces éléments est loin d'être exhaustif, mais j'espère que cela vous donnera un point de départ.
J'ai écrit un article qui résume la différence entre les deux et aide à choisir quand utiliser l'un ou l'autre.
Partager l'état - quand utiliser les vars, les atomes, les agents et les refs ?
J'espère que cela aidera les personnes qui cherchent des réponses dans ce domaine.
Quelques raccourcis de l'article après la suggestion de @tunaci :
Vars
Les variables sont globales pour tous les threads.
Ne pas modifier les variables après la création. C'est techniquement possible, mais c'est mauvaise idée pour de nombreuses raisons.
Atomes
Partager l'accès à l'état mutable pour tous les threads. Le changement se produit de manière synchrone. Réessayer quand un autre thread change l'état pendant l'exécution.
N'utilisez pas de fonctions non idempotentes et de fonctions avec un temps d'exécution long. d'exécution
Agents
Partager l'accès à l'état mutable pour tous les threads. Le changement se produit de manière asynchrone.
Réf.
Refs fonctionne de manière similaire aux transactions de la base de données. L'écriture et la lecture sont protégées en dosync. Vous pouvez opérer sur plusieurs refs en toute sécurité dans une transaction.
Et organigramme quand utiliser lequel :
Veuillez regarder l'image sur le site web, car des mises à jour sont toujours possibles.
C'est un sujet complexe et long pour donner une réponse complète sans copier et coller l'article, donc s'il vous plaît pardonnez-moi je vous redirige vers le site web :)
Atomes, réfs et agents - un peu de lumière ici http://blog.jayfields.com/2011/04/clojure-state-management.html