Wie unterscheiden sich Clojure-Futures und -Versprechen?

86

Sowohl Futures als auch Versprechen blockieren, bis sie ihre Werte berechnet haben. Was ist also der Unterschied zwischen ihnen?

appshare.co
quelle
8
Ich bin nicht sicher, warum die -1 auf der Frage, oder sind Fragen, bei denen Sie die Antwort nicht kennen, bevor Sie jetzt schlechte Dinge fragen?
NUR MEINE RICHTIGE MEINUNG
Ich habe keine der Antworten -1? Wie können wir feststellen, wer -1 auf eine Frage oder Antwort gesetzt hat?
appshare.co
Du und ich können nicht, Zubair. Ich bin nur neugierig, wer Ihre Frage mit -1 bewertet hat, da dies eine absolut vernünftige Frage ist und für SO definitiv ein Thema ist.
NUR MEINE RICHTIGE MEINUNG

Antworten:

53

In Clojure-Begriffen antworten, hier einige Beispiele aus Sean Devlins Screencast :

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

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

Beachten Sie, dass Sie im Versprechen explizit einen Wert liefern, den Sie in einer späteren Berechnung ( :fredin diesem Fall) auswählen . Die Zukunft hingegen wird an dem Ort konsumiert, an dem sie geschaffen wurde. Das some-exprwird vermutlich hinter den Kulissen gestartet und (eventuell) im Tandem berechnet. Wenn es jedoch zum Zeitpunkt des Zugriffs nicht bewertet wird, werden die Thread-Blöcke bis zur Verfügbarkeit angezeigt.


bearbeitet, um hinzuzufügen

Beachten Sie Folgendes, um die Unterscheidung zwischen einem Versprechen und einer Zukunft zu erleichtern:

versprechen

  1. Sie erstellen eine promise. Dieses Versprechungsobjekt kann jetzt an einen beliebigen Thread übergeben werden.
  2. Sie fahren mit den Berechnungen fort. Dies können sehr komplizierte Berechnungen sein, die Nebenwirkungen, das Herunterladen von Daten, Benutzereingaben, Datenbankzugriff und andere Versprechen beinhalten - was auch immer Sie möchten. Der Code ähnelt in jedem Programm Ihrem Hauptcode.
  3. Wenn Sie fertig sind, können Sie deliverdie Ergebnisse für dieses Versprechenobjekt anzeigen.
  4. Jeder Gegenstand, der versucht, derefIhr Versprechen zu erfüllen, bevor Sie mit Ihrer Berechnung fertig sind, wird blockiert, bis Sie fertig sind. Sobald Sie fertig sind und deliverdas Versprechen eingelöst haben, wird das Versprechen nicht mehr blockiert.

Zukunft

  1. Sie schaffen Ihre Zukunft. Ein Teil Ihrer Zukunft ist ein Ausdruck für die Berechnung.
  2. Die Zukunft kann gleichzeitig ausgeführt werden oder nicht. Es könnte ein Thread zugewiesen werden, möglicherweise aus einem Pool. Es konnte einfach warten und nichts tun. Aus Ihrer Sicht können Sie nicht sagen .
  3. Irgendwann bist du (oder ein anderer Thread) derefdie Zukunft. Wenn die Berechnung bereits abgeschlossen ist, erhalten Sie die Ergebnisse. Wenn es noch nicht abgeschlossen ist, blockieren Sie, bis es abgeschlossen ist. (Wenn es vermutlich noch nicht gestartet wurde, derefbedeutet dies, dass es ausgeführt wird, aber auch dies ist nicht garantiert.)

Während Sie den Ausdruck in Zukunft so kompliziert machen könnten wie den Code, der auf die Erstellung eines Versprechens folgt, ist es zweifelhaft, dass dies wünschenswert ist. Dies bedeutet, dass Futures eher für schnelle, hintergrundfähige Berechnungen geeignet sind, während Versprechen eher für große, komplizierte Ausführungspfade geeignet sind. Außerdem scheinen Versprechen in Bezug auf die verfügbaren Berechnungen etwas flexibler und auf den Versprechensschöpfer ausgerichtet zu sein, der die Arbeit erledigt, und auf einen anderen Faden, der die Ernte erntet. Futures sind eher darauf ausgerichtet, einen Thread automatisch zu starten (ohne den hässlichen und fehleranfälligen Overhead) und mit anderen Dingen fortzufahren, bis Sie - der ursprüngliche Thread - die Ergebnisse benötigen.

NUR MEINE RICHTIGE MEINUNG
quelle
Sie können jedoch einen beliebigen Berechnungsblock haben, bis entweder ein Versprechen oder eine Zukunft abgeschlossen ist. dh: (@a + @b) wird mit einer Zukunft und einem Versprechen gleich
funktionieren
2
Ein Versprechen ermöglicht mir mehr Flexibilität. Ich mache ein Versprechen. Ich gebe dieses Versprechen an einen anderen Thread weiter. Ich kann dann viele komplizierte Berechnungen durchführen, einschließlich Warten auf E / A, Herunterladen von Daten aus dem Internet, Warten auf Benutzereingaben usw. Wenn alles erledigt ist, gebe ich das Versprechen mit dem resultierenden Wert ab. Eine Zukunft umfasst einen S-Ausdruck. Es könnte ein sehr, sehr komplizierter S-Ausdruck sein, aber es wäre ein bisschen ... starr dort. Außerdem erledigt eine Zukunft ihre Arbeit automatisch in einem Thread (oder Pool). Dasselbe in einem Versprechen zu tun, würde noch mehr Arbeit bedeuten.
NUR MEINE RICHTIGE MEINUNG
FWIW Da ein einzelner s-Ausdruck ein Aufruf eines beliebigen Codepfads sein kann, geht es nicht unbedingt darum, wie viel Code Sie in den Ausdruck packen können. Anstatt zu sagen, dass ein Versprechen "flexibler" ist, würde ich sagen, dass sein Zweck einfach anders ist. Warum sonst beides?
Geoff
2
Nur zur futureVeranschaulichung , der Hauptteil eines Anrufs kann N sexprs enthalten.
vemv
Diese Erklärung sollte Teil von Clojure Doc
Piyush Katariya
24

Sowohl Future als auch Promise sind Mechanismen zur Kommunikation des Ergebnisses asynchroner Berechnungen vom Produzenten an den Verbraucher.

Im Falle von Future wird die Berechnung zum Zeitpunkt der Future-Erstellung definiert und die asynchrone Ausführung beginnt "ASAP". Es "weiß" auch, wie eine asynchrone Berechnung erzeugt wird.

Im Falle des Versprechens werden die Berechnung , die Startzeit und der [mögliche] asynchrone Aufruf vom Übermittlungsmechanismus entkoppelt. Wenn das Berechnungsergebnis verfügbar ist, muss der Produzent deliverexplizit aufrufen. Dies bedeutet auch, dass der Produzent steuert, wann das Ergebnis verfügbar wird.

Für Versprechen macht Clojure einen Entwurfsfehler, indem er dasselbe Objekt (Ergebnis des promiseAufrufs) verwendet, um das Ergebnis der Berechnung zu erzeugen ( deliver) und zu verbrauchen ( deref) . Dies sind zwei sehr unterschiedliche Fähigkeiten, die als solche behandelt werden sollten.

Dimagog
quelle
@oskarkv Angenommen, Sie haben ein Versprechen erstellt und es 3 Kunden gegeben. Nichts hindert einen der Clients daran, es mit einem falschen Ergebnis aufzulösen und es zwei anderen Clients zu signalisieren. Außerdem können Sie dieses Versprechen nicht mehr lösen. Im Gegensatz dazu wird dieses Szenario unmöglich, wenn Sie ein Paar aus Versprechen und Resolver hatten, Ihren Kunden Versprechen gaben und Resolver für sich behalten. Weitere Informationen zu den vorgeschlagenen Suchbegriffen sind "funktionsbasierte Zugriffskontrolle" und "funktionsbasierte Sicherheit".
Dimagog
1
Ich bin mir nicht sicher, ob promisees bequem wäre, die Sicherheit an einen so einfachen Referenztyp zu koppeln (siehe Impl) . "Böse" Verbraucher sind selten; Nichts hindert Sie daran, Ihre eigene Abstraktion auf Versprechungen aufzubauen.
vemv
8
Es geht nicht um Sicherheit, es kommt nur so vor, dass fähigkeitsbasierte Programmierung oft in Bezug auf Sicherheit beschrieben wird. Hier dreht sich alles um Codekorrektheit. Der häufig verwendete Begriff lautet "Konstruktionsrichtig" und die Frage lautet: "Können Sie ein falsches Programm erstellen?" Nicht absichtlich, sondern aus Versehen. Mit einem einzelnen Promise-Objekt können Sie, mit zwei separaten Objekten nicht.
Dimagog
Nichts hindert Sie daran, ein Versprechen zurückzugeben, das jedoch nicht (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))))
erfüllt werden
Der Hinweis auf den Unterschied, wie der Berechnungsmechanismus entkoppelt ist, machte diesen Beitrag zu einer wirklich präzisen Erklärung. Vielen Dank!
Synthomat
3

Es gibt bereits hervorragende Antworten, daher wird nur die Zusammenfassung "Verwendung" hinzugefügt:

Beide

Wenn Sie ein Versprechen oder eine Zukunft erstellen, wird sofort eine Referenz zurückgegeben. Diese Referenz blockiert @ / deref, bis das Ergebnis der Berechnung von einem anderen Thread bereitgestellt wird.

Zukunft

Beim Erstellen einer Zukunft stellen Sie einen synchronen Job bereit, der ausgeführt werden muss. Es wird in einem Thread aus dem dedizierten unbegrenzten Pool ausgeführt.

Versprechen

Sie geben keine Argumente an, wenn Sie ein Versprechen erstellen. Die Referenz sollte an einen anderen 'Benutzer'-Thread übergeben werden, der deliverdas Ergebnis liefert.

Grzegorz Luczywo
quelle
1

In Clojure, promise, future, und delaysind Versprechen ähnliche Objekte. Sie alle stellen eine Berechnung dar, auf die Clients mit deref(oder @) warten können . Clients verwenden das Ergebnis erneut, sodass die Berechnung nicht mehrmals ausgeführt wird.

Sie unterscheiden sich in der Art und Weise, wie die Berechnung durchgeführt wird:

  • futurestartet die Berechnung in einem anderen Worker-Thread. derefwird blockiert, bis das Ergebnis fertig ist.

  • delayführt die Berechnung träge durch, wenn der erste Client verwendet deref, oder force.

  • promisebietet die größte Flexibilität, da das Ergebnis durch Verwendung auf jede benutzerdefinierte Weise geliefert wird deliver. Sie verwenden es, wenn keines futureoder delayIhr Anwendungsfall übereinstimmt.

Ernesto
quelle
-4

Erstens ist a Promisea Future. Ich denke, Sie möchten den Unterschied zwischen a Promiseund a kennen FutureTask.

A Futurestellt einen Wert dar, der derzeit nicht bekannt ist, aber in Zukunft bekannt sein wird.

A FutureTaskstellt das Ergebnis einer Berechnung dar, die in Zukunft stattfinden wird (möglicherweise in einem Thread-Pool). Wenn Sie versuchen, auf das Ergebnis zuzugreifen, wird die Berechnung blockiert, wenn sie noch nicht erfolgt ist. Andernfalls wird das Ergebnis sofort zurückgegeben. Es ist keine andere Partei an der Berechnung des Ergebnisses beteiligt, da die Berechnung von Ihnen im Voraus festgelegt wurde.

A Promisestellt ein Ergebnis dar, das der Versprechende dem Versprechenden in Zukunft liefern wird. In diesem Fall sind Sie der Versprechende und der Versprechende ist derjenige, der Ihnen das PromiseObjekt gegeben hat. Ähnlich wie bei FutureTask, wenn Sie versuchen, auf das Ergebnis zuzugreifen, bevor das Promiseerfüllt wurde, wird es blockiert, bis der Promiser das erfüllt Promise. Sobald das Promiseerfüllt ist, erhalten Sie immer und sofort den gleichen Wert. Im Gegensatz zu a FutureTaskist hier eine andere Partei beteiligt, die die Promise. Dass eine andere Partei für die Berechnung und Erfüllung der Promise.

In diesem Sinne ist a FutureTaskein, das Promisedu dir selbst gemacht hast.

Abhinav Sarkar
quelle
Sind Sie sicher, dass ein Versprechen eine Zukunft ist? Ich kann nicht finden, dass es die Schnittstelle implementiert. github.com/richhickey/clojure/blob/…
Mikael Sundberg
Entschuldigung, ich habe die Eingabe falsch gedrückt. Meine Frage wurde geändert
Mikael Sundberg
Meine Antwort ist im Allgemeinen und nicht im Clojure-spezifischen Sinne.
Abhinav Sarkar
9
Die Beantwortung einer Frage zu Clojure mit Java-Code erscheint etwas skurril.
NUR MEINE RICHTIGE MEINUNG