Was ist der Unterschied zwischen Future
y Promise
?
Beide wirken wie ein Platzhalter für künftige Ergebnisse, aber wo liegt der Hauptunterschied?
Antworten
Zu viele Anzeigen?(Ich bin mit den bisherigen Antworten nicht ganz zufrieden, deshalb hier mein Versuch...)
Ich denke, dass Der Kommentar von Kevin Wright
Sie können ein Versprechen abgeben, und es liegt an Ihnen, es einzuhalten. Wenn dir jemand anderes ein Versprechen gibt, musst du abwarten, ob er es in der Zukunft einhält.
fasst es ziemlich gut zusammen, aber eine Erklärung kann nützlich sein.
Zukünfte und Versprechen sind ziemlich ähnliche Konzepte, der Unterschied besteht darin, dass ein Future ein schreibgeschützter Container für ein noch nicht vorhandenes Ergebnis ist, während ein Versprechen geschrieben werden kann (normalerweise nur einmal). Die Java 8 ErfüllbarZukunft und die Guave SettableFuture können als Versprechen betrachtet werden, da ihr Wert gesetzt ("abgeschlossen") werden kann, aber sie implementieren auch die Future-Schnittstelle, so dass es für den Client keinen Unterschied gibt.
Das Ergebnis der Zukunft wird von "jemand anderem" festgelegt - durch das Ergebnis einer asynchronen Berechnung. Beachten Sie, wie FutureTask - eine klassische Zukunft - muss mit einem Callable oder Runnable initialisiert werden, es gibt keinen No-Argument-Konstruktor, und sowohl Future als auch FutureTask sind von außen nur lesbar (die Set-Methoden von FutureTask sind geschützt). Der Wert wird auf das Ergebnis der Berechnung von innen gesetzt.
Andererseits kann das Ergebnis eines Versprechens jederzeit von "Ihnen" (oder eigentlich von jedem) gesetzt werden, da es eine öffentliche Setter-Methode hat. Sowohl CompletableFuture als auch SettableFuture können ohne eine Aufgabe erstellt werden, und ihr Wert kann jederzeit gesetzt werden. Sie senden ein Versprechen an den Client-Code und lösen es später ein, wenn Sie es wünschen.
Beachten Sie, dass CompletableFuture kein "reines" Versprechen ist. Es kann wie FutureTask mit einer Aufgabe initialisiert werden, und seine nützlichste Eigenschaft ist die unverbundene Verkettung von Verarbeitungsschritten.
Beachten Sie auch, dass ein Versprechen kein Untertyp von future sein muss und dass es sich nicht um das gleiche Objekt handeln muss. In Scala wird ein Future-Objekt durch eine asynchrone Berechnung oder durch eine verschiedene Objekt versprechen. In C++ ist die Situation ähnlich: Das Promise-Objekt wird vom Produzenten und das Future-Objekt vom Konsumenten verwendet. Der Vorteil dieser Trennung ist, dass der Client den Wert des future nicht festlegen kann.
Beide Frühling y EJB 3.1 haben eine AsyncResult-Klasse, die den Scala/C++-Versprechen ähnlich ist. AsyncResult implementiert Future, aber das ist nicht die wirkliche Zukunft: Asynchrone Methoden in Spring/EJB geben ein anderes, schreibgeschütztes Future-Objekt durch irgendeine Hintergrundmagie zurück, und diese zweite "echte" Zukunft kann vom Client für den Zugriff auf das Ergebnis verwendet werden.
Selon le diese Diskussion , Promise
ist endlich aufgerufen worden CompletableFuture
zur Aufnahme in Java 8, und seine Javadoc erklärt:
Ein Future, der explizit abgeschlossen werden kann (wobei sein Wert und Status festgelegt werden) und als CompletionStage verwendet werden kann, der abhängige Funktionen und Aktionen unterstützt, die bei seinem Abschluss ausgelöst werden.
Ein Beispiel ist ebenfalls in der Liste aufgeführt:
f.then((s -> aStringFunction(s)).thenAsync(s -> ...);
Die endgültige API ist etwas anders, ermöglicht aber eine ähnliche asynchrone Ausführung:
CompletableFuture<String> f = ...;
f.thenApply(this::modifyString).thenAccept(System.out::println);
Ich bin mir bewusst, dass es bereits eine akzeptierte Antwort gibt, aber ich möchte trotzdem meinen Senf dazugeben:
TLDR: Future und Promise sind die beiden Seiten einer asynchronen Operation: Verbraucher/Anrufer vs. Hersteller/Implementierer .
Als Anrufer einer asynchronen API-Methode, erhalten Sie eine Future
als Zugriff auf das Ergebnis der Berechnung. Sie können z.B. aufrufen get()
um auf den Abschluss der Berechnung zu warten und das Ergebnis abzurufen.
Denken Sie nun daran, wie diese API-Methode tatsächlich implementiert wird: Die . muss eine Future
sofort. Sie sind dafür verantwortlich, diesen Future zu beenden, sobald die Berechnung abgeschlossen ist (was sie wissen werden, weil sie die Versandlogik implementieren ;-)). Sie verwenden eine Promise
/ CompletableFuture
um genau das zu tun: Konstruieren und Zurückgeben der CompletableFuture
sofort, und rufen Sie complete(T result)
sobald die Berechnung abgeschlossen ist.
Ich werde ein Beispiel dafür geben, was Promise ist und wie sein Wert jederzeit gesetzt werden kann, im Gegensatz zu Future, dessen Wert nur lesbar ist.
Angenommen, du hast eine Mutter und bittest sie um Geld.
// Now , you trick your mom into creating you a promise of eventual
// donation, she gives you that promise object, but she is not really
// in rush to fulfill it yet:
Supplier<Integer> momsPurse = ()-> {
try {
Thread.sleep(1000);//mom is busy
} catch (InterruptedException e) {
;
}
return 100;
};
ExecutorService ex = Executors.newFixedThreadPool(10);
CompletableFuture<Integer> promise =
CompletableFuture.supplyAsync(momsPurse, ex);
// You are happy, you run to thank you your mom:
promise.thenAccept(u->System.out.println("Thank you mom for $" + u ));
// But your father interferes and generally aborts mom's plans and
// completes the promise (sets its value!) with far lesser contribution,
// as fathers do, very resolutely, while mom is slowly opening her purse
// (remember the Thread.sleep(...)) :
promise.complete(10);
Das Ergebnis ist:
Thank you mom for $10
Das Versprechen der Mutter wurde erstellt, wartete aber auf ein "Vollendungs"-Ereignis.
CompletableFuture<Integer> promise...
Sie haben ein solches Ereignis geschaffen, indem Sie ihr Versprechen angenommen und Ihre Pläne angekündigt haben, um Ihrer Mutter zu danken:
promise.thenAccept...
In diesem Moment begann Mama ihre Handtasche zu öffnen...aber sehr langsam...
und Vater hat sich viel schneller eingemischt und das Versprechen anstelle deiner Mutter eingelöst:
promise.complete(10);
Ist Ihnen ein Executor aufgefallen, den ich explizit geschrieben habe?
Interessanterweise, wenn Sie stattdessen einen impliziten Standard-Executor verwenden (commonPool) und der Vater nicht zu Hause ist, sondern nur die Mutter mit ihrem "langsamen Geldbeutel", dann wird ihr Versprechen nur erfüllt, wenn das Programm länger lebt als die Mutter braucht, um Geld von t
T
Ich bin mir nicht sicher, ob dies eine Antwort sein kann, aber so wie ich sehe, was andere gesagt haben, könnte es für jemanden so aussehen, als bräuchte man zwei getrennte Abstraktionen für diese beiden Konzepte, so dass eines von ihnen ( Future
) ist nur eine Nur-Lese-Ansicht der anderen ( Promise
) ... aber eigentlich ist das nicht nötig.
Sehen Sie sich zum Beispiel an, wie Versprechen in Javascript definiert sind:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
Der Schwerpunkt liegt auf der Zusammensetzbarkeit mit dem then
Methode wie:
asyncOp1()
.then(function(op1Result){
// do something
return asyncOp2();
})
.then(function(op2Result){
// do something more
return asyncOp3();
})
.then(function(op3Result){
// do something even more
return syncOp4(op3Result);
})
...
.then(function(result){
console.log(result);
})
.catch(function(error){
console.log(error);
})
was asynchrone Berechnungen wie synchrone aussehen lässt:
try {
op1Result = syncOp1();
// do something
op1Result = syncOp2();
// do something more
op3Result = syncOp3();
// do something even more
syncOp4(op3Result);
...
console.log(result);
} catch(error) {
console.log(error);
}
was ziemlich cool ist. (Nicht so cool wie async-await mais async-await entfernt lediglich den Textbaustein ....then(function(result) {.... von ihm).
Und eigentlich ist ihre Abstraktion ziemlich gut, da der Versprechungskonstruktor
new Promise( function(resolve, reject) { /* do it */ } );
ermöglicht es Ihnen, zwei Rückrufe bereitzustellen, die entweder zur Vervollständigung der Promise
erfolgreich oder mit einem Fehler. So dass nur der Code, der die Promise
vervollständigen kann und der Code, der eine bereits konstruierte Promise
Objekt hat die Nur-Lese-Ansicht.
Mit Vererbung kann das oben Genannte erreicht werden, wenn beheben y zurückweisen sind geschützte Methoden.
- See previous answers
- Weitere Antworten anzeigen