Je suis conscient que c'est généralement une mauvaise pratique de mettre des fonctions avec des effets secondaires dans les transactions STM, car ils peuvent potentiellement être récupérés et appelés plusieurs fois.
Il me surprenda ce que vous pourriez utiliser des agents pour vous assurer que que les effets secondaires ne sont exécutés qu'après la fin de la transaction terminée. p>
(dosync // transactional stuff (send some-agent #(function-with-side-effects params)) // more transactional stuff )
3 Réponses :
On dirait que cela devrait travailler pour moi. Selon les effets secondaires, vous voudrez peut-être utiliser l'envoi (pour les OPS io-liés) au lieu d'envoyer (pour les OPS liées à la CPU). L'envoi / envoi fera en conclusion de la tâche dans l'un des pools d'exécutants de l'agent interne (il y a un pool de taille fixe pour la CPU et la piscine de taille sans bornes pour IO OPS). Une fois que la tâche est en cours, le travail est éteint le fil de la DOSYNC, donc vous êtes déconnecté à ce point. P>
Vous devez capturer toutes les valeurs dont vous avez besoin de la transaction dans la fonction envoyée bien sûr. Et vous devez faire face à cet envoi éventuellement plusieurs fois en raison de tentatives. P>
Mise à jour (voir Commentaires): strong> p>
L'agent envoie dans la transaction de Ref est détenu jusqu'à ce que la transaction REF se termine et sont exécutées une fois. Donc, dans ma réponse ci-dessus, l'envoi ne se produira pas plusieurs fois, mais il ne se produira pas pendant la transaction Ref, ce qui peut ne pas être ce que vous voulez (si vous vous attendez à vous connecter ou à faire des trucs latéraux). P>
@Mikera, @alex, l'envoi est garantie de se produire une seule fois après la réussite de la transaction et ne devrait pas se produire plusieurs fois. (Déclaration 5 dans clojure.org/agents )
@bmillare - Je pense que vous parlez de quelque chose d'autre. Cette déclaration fait référence à la manière dont la fonction passée dans un envoi / envoi sera exécutée sera exécutée. Ce que je dis, c'est que, en faisant cet appel à l'intérieur de la transaction Ref, la transaction Réf i> peut être récupérée à l'origine de plusieurs appels d'envoi / envoi, chacun d'eux qui exécute exactement une fois.
@ALEX, Excusez-moi, j'ai réfléchi au mauvais point, en outre dans le texte, il est indiqué que "les agents sont intégrés à la STM - toutes les dépêches effectuées dans une transaction sont conservées jusqu'à ce qu'il s'engage et sont jetées si elles sont recessions ou abandonnées."
@bmillare hmmm .... Je vois ton point. Je ne suis toujours pas sûr que j'accepte que c'est ce qui se passera comme je ne sais pas qu'un envoi dans une transaction de REF aura la même contrainte. Pourrait être temps d'écrire un petit code pour savoir ...
@bmillare en effet, vous êtes correct. Un agent envoie de l'intermédiaire de la transaction REF aura lieu et exécuté à la fin de la transaction Ref réussie. Donc, @Mikera ma réponse originale ci-dessus était incorrecte.
Merci gars - extrêmement utile et semble faire exactement ce que je veux (c'est-à-dire un effet secondaire déclenché une seule fois si et seulement si la transaction réussit)
Cela fonctionne et est une pratique courante. Cependant, comme Alex a souligné à juste titre que vous devriez envisager de renvoyer l'envoi.
Il existe plus de moyens de capturer des valeurs commises et de les remédier à la transaction. Par exemple, vous pouvez les renvoyer dans un vecteur (ou une carte ou autre). P> ou vous pouvez appeler réinitialiser! sur un atome local (défini à l'extérieur de la portée lexicale du bloc Dosync bien sûr). p> p>
Il n'y a rien de mal à utiliser des agents, mais il suffit de revenir à partir des valeurs de transaction nécessaires au calcul sur latéral suffisamment suffisant.
REFS est probablement le moyen le plus propre de le faire, mais vous pouvez même le gérer avec juste des atomes ! p> le swap! code> peut réessayer autant de fois que nécessaire, mais la file d'attente de travail ne sera jamais plus grande que trois, et vous allez toujours imprimer exactement une fois em> un message attaché correctement à l'acceptation de votre élément de travail. La "conception originale" a appelé juste un seul Int dans l'atome, mais vous pouvez le transformer en une paire afin de transmettre des données intéressantes hors du calcul. P> p>
L'une des idées de base de la STM est l'atomicité de la défaillance. Comment cela pourrait-il aider avec ça?
Le point concerne les effets secondaires qui doivent survenir après une transaction réussit mais ne font pas partie de la transaction, par ex. Envoi d'un email de confirmation. Clairement, vous ne voulez pas faire cela chaque fois que la transaction tente ou autre que vous pourriez obtenir un destinataire très en colère / confus!