En quoi les futurs et les promesses de Clojure diffèrent-ils?

86

Les futurs et les promesses se bloquent jusqu'à ce qu'ils aient calculé leurs valeurs, alors quelle est la différence entre eux?

appshare.co
la source
8
Je ne sais pas pourquoi le -1 sur la question, ou des questions dont vous ne connaissez pas la réponse avant de poser maintenant de mauvaises choses?
JUSTE MON OPINION correcte
Je n'ai pas -1 aucune des réponses ?? Comment savoir qui a mis -1 sur une question ou une réponse?
appshare.co
Toi et moi ne pouvons pas, Zubair. Je suis simplement curieux de savoir qui a mis un -1 sur votre question étant donné que c'est une question parfaitement raisonnable à poser et que c'est définitivement un sujet pour SO.
JUSTE MON OPINION correcte

Réponses:

54

Répondant en termes de Clojure, voici quelques exemples tirés du screencast de Sean Devlin :

(def a-promise (promise))
(deliver a-promise :fred)

(def f (future (some-sexp)))
(deref f)

Notez que dans la promesse, vous fournissez explicitement une valeur que vous sélectionnez dans un calcul ultérieur ( :freddans ce cas). L'avenir, par contre, est consommé au même endroit où il a été créé. Le some-exprest probablement lancé dans les coulisses et calculé en tandem (éventuellement), mais s'il reste non évalué au moment où il est accédé, le thread se bloque jusqu'à ce qu'il soit disponible.


modifié pour ajouter

Pour mieux faire la distinction entre une promesse et un avenir, notez ce qui suit:

promettre

  1. Vous créez un promise. Cet objet de promesse peut maintenant être passé à n'importe quel thread.
  2. Vous continuez avec les calculs. Il peut s'agir de calculs très compliqués impliquant des effets secondaires, le téléchargement de données, l'entrée de l'utilisateur, l'accès à la base de données, d'autres promesses - tout ce que vous voulez. Le code ressemblera beaucoup à votre code principal dans n'importe quel programme.
  3. Lorsque vous avez terminé, vous pouvez obtenir deliverles résultats de cet objet promis.
  4. Tout élément qui tente de tenir derefvotre promesse avant que vous ayez terminé votre calcul sera bloqué jusqu'à ce que vous ayez terminé. Une fois que vous avez terminé et que vous avez exécuté deliverla promesse, la promesse ne se bloquera plus.

futur

  1. Vous créez votre avenir. Une partie de votre avenir est une expression de calcul.
  2. L'avenir peut ou non s'exécuter simultanément. Il pourrait être assigné à un thread, éventuellement à partir d'un pool. Il pourrait juste attendre et ne rien faire. De votre point de vue, vous ne pouvez pas le dire .
  3. À un moment donné, vous (ou un autre thread) êtes derefl'avenir. Si le calcul est déjà terminé, vous en obtenez les résultats. Si ce n'est pas déjà fait, vous bloquez jusqu'à ce que ce soit le cas. (Probablement s'il n'a pas encore démarré, derefcela signifie qu'il commence à s'exécuter, mais cela n'est pas non plus garanti.)

Bien que vous puissiez rendre l'expression à l'avenir aussi compliquée que le code qui suit la création d'une promesse, il est peu probable que ce soit souhaitable. Cela signifie que les contrats à terme sont vraiment plus adaptés aux calculs rapides et en arrière-plan, tandis que les promesses sont vraiment plus adaptées aux chemins d'exécution longs et complexes. Aussi, les promesses semblent, en termes de calculs disponibles, un peu plus flexibles et orientées vers le créateur de promesses faisant le travail et un autre fil récoltant la récolte. Les contrats à terme sont davantage orientés vers le démarrage automatique d'un thread (sans la surcharge laide et sujette aux erreurs) et vers d'autres choses jusqu'à ce que vous - le thread d'origine - ayez besoin des résultats.

JUSTE MON AVIS correct
la source
Mais vous pouvez avoir n'importe quel bloc de calcul jusqu'à ce qu'une promesse OU un avenir soit terminé. ie: (@a + @b) fonctionnera de la même manière avec un avenir et une promesse
appshare.co
2
Une promesse permet plus de flexibilité à mon avis. Je crée une promesse. Je passe cette promesse à un autre fil. Je peux alors faire beaucoup de calculs compliqués, y compris l'attente des E / S, le téléchargement des données depuis Internet, l'attente des entrées de l'utilisateur, etc. Quand tout est fait, je livre la promesse avec la valeur qui en résulte. Un futur recouvre une seule expression S. Cela pourrait, je suppose, être une expression S très, très compliquée, mais ce serait un peu ... rigide ici. De plus un futur fait son travail automatiquement dans un thread (ou pool). Faire la même chose dans une promesse signifierait encore plus de travail.
JUSTE MON OPINION correcte
FWIW puisqu'une seule expression s peut être un appel à un chemin de code arbitraire, il ne s'agit pas nécessairement de la quantité de code que vous pouvez entasser dans l'expression. Donc, au lieu de dire qu'une promesse est «plus flexible», je dirais que son objectif est tout simplement différent. Sinon, pourquoi avoir les deux?
Geoff
2
Pour mémoire, le corps d'un futureappel peut inclure N sexprs.
vemv du
Cette explication devrait faire partie de Clojure Doc
Piyush Katariya
25

Future et Promise sont des mécanismes pour communiquer le résultat du calcul asynchrone du producteur au (x) consommateur (s).

Dans le cas de Future, le calcul est défini au moment de la création Future et l'exécution asynchrone commence "ASAP". Il "sait" également comment générer un calcul asynchrone.

Dans le cas de Promise, le calcul , son heure de début et son [possible] appel asynchrone sont découplés du mécanisme de livraison. Lorsque le résultat du calcul est disponible, le producteur doit appeler deliverexplicitement, ce qui signifie également que le producteur contrôle le moment où le résultat devient disponible.

Pour les promesses, Clojure commet une erreur de conception en utilisant le même objet (résultat de l' promiseappel) pour produire ( deliver) et consommer ( deref) le résultat du calcul . Ce sont deux capacités très distinctes et doivent être traitées comme telles.

Dimagog
la source
@oskarkv Supposons que vous ayez créé une promesse et l'ayez donnée à 3 clients. Rien n'empêche l'un des clients de le résoudre avec un résultat faux et de le signaler à deux autres clients. De plus, vous ne pourrez plus résoudre cette promesse. En revanche, si vous aviez une paire promesse + résolveur, donniez une promesse à vos clients et gardiez le résolveur pour vous-même, ce scénario devient impossible. Pour plus d'informations, les termes de recherche suggérés sont «contrôle d'accès basé sur les capacités» et «sécurité basée sur les capacités».
Dimagog
1
Je ne sais pas si le couplage de la sécurité à un type de référence aussi simple (consultez son impl) promiseserait pratique. Les consommateurs «mauvais» sont rares; rien ne vous empêche de construire votre propre abstraction en plus de promesses.
vemv
8
Il ne s'agit pas de sécurité, il se trouve que la programmation basée sur les capacités est souvent décrite en relation avec la sécurité. Ici, tout est question de correction du code. Le terme souvent utilisé est «correct par construction» et la question est «pouvez-vous construire un programme incorrect»? Pas exprès, mais par accident. Avec un seul objet Promise, vous pouvez, alors qu'avec deux objets séparés, vous ne pouvez pas.
Dimagog
Rien ne vous empêche de retourner une promesse qui ne peut être tenue si c'est ce que vous voulez: (defn undeliverable-promise [] (let [p (promise)] (reify clojure.lang.IDeref (deref [_] (deref p)) clojure.lang.IBlockingDeref (deref [_ ms val] (deref p ms val)) clojure.lang.IPending (isRealized [_] (.isRealized p)) clojure.lang.IFn (invoke [_ _] nil))))
tapichu
Soulignant la différence de découplage du mécanisme de calcul a fait de cet article une explication vraiment concise. Merci!
synthomat
3

Il y a déjà d'excellentes réponses donc n'ajoutez que le résumé "comment utiliser":

Tous les deux

La création d'une promesse ou d'un futur renvoie une référence immédiatement. Cette référence se bloque sur @ / deref jusqu'à ce que le résultat du calcul soit fourni par un autre thread.

Futur

Lors de la création du futur, vous fournissez un travail synchrone à faire. Il est exécuté dans un thread du pool illimité dédié.

Promettre

Vous ne donnez aucun argument lors de la création de la promesse. La référence doit être passée à un autre thread «utilisateur» qui donnera deliverle résultat.

Grzegorz Luczywo
la source
1

En Clojure, promise, futureet delaysont la promesse comme des objets. Ils représentent tous un calcul que les clients peuvent attendre en utilisant deref(ou @). Les clients réutilisent le résultat, de sorte que le calcul ne soit pas exécuté plusieurs fois.

Ils diffèrent dans la manière dont le calcul est effectué:

  • futuredémarrera le calcul dans un thread de travail différent. derefbloquera jusqu'à ce que le résultat soit prêt.

  • delayeffectuera le calcul paresseusement, lorsque le premier client utilise deref, ou force.

  • promiseoffre la plus grande flexibilité, car son résultat est fourni de manière personnalisée en utilisant deliver. Vous l'utilisez lorsque ni futureni ne delaycorrespond à votre cas d'utilisation.

Ernesto
la source
-4

Premièrement, a Promiseest un Future. Je pense que vous voulez connaître la différence entre a Promiseet a FutureTask.

A Futurereprésente une valeur qui n'est pas connue actuellement mais qui sera connue dans le futur.

A FutureTaskreprésente le résultat d'un calcul qui se produira à l'avenir (peut-être dans un pool de threads). Lorsque vous essayez d'accéder au résultat, si le calcul n'a pas encore eu lieu, il se bloque. Sinon, le résultat est renvoyé immédiatement. Il n'y a aucune autre partie impliquée dans le calcul du résultat car le calcul est spécifié par vous à l'avance.

A Promisereprésente un résultat qui sera livré par le promettant au promettant à l'avenir. Dans ce cas, vous êtes le promis et le prometteur est celui qui vous a donné l' Promiseobjet. Semblable à la FutureTask, si vous essayez d'accéder au résultat avant que le Promisen'ait été exécuté, il est bloqué jusqu'à ce que le prometteur remplisse le Promise. Une fois que le Promiseest rempli, vous obtenez toujours et immédiatement la même valeur. Contrairement à a FutureTask, il y a une autre partie impliquée ici, une qui a fait le Promise. Qu'une autre partie est responsable du calcul et de l'exécution du Promise.

En ce sens, un FutureTaskest un Promisevous fait pour vous-même.

Abhinav Sarkar
la source
Êtes-vous sûr qu'une promesse est un avenir? je ne trouve pas qu'il implémente l'interface. github.com/richhickey/clojure/blob/…
Mikael Sundberg
désolé, j'ai mal appuyé sur entrer. Ma question est modifiée
Mikael Sundberg
Ma réponse est dans un sens général, pas dans un sens spécifique à Clojure.
Abhinav Sarkar le
9
Répondre à une question sur Clojure avec du code Java semble un peu fantaisiste.
JUSTE MON OPINION correcte