Qual è la differenza tra Future
e Promise
?
Entrambi agiscono come segnaposto per risultati futuri, ma dov'è la differenza principale?
Qual è la differenza tra Future
e Promise
?
Entrambi agiscono come segnaposto per risultati futuri, ma dov'è la differenza principale?
Risposte:
Secondo questa discussione , Promise
è stato finalmente richiesto l' CompletableFuture
inclusione in Java 8 e il suo javadoc spiega:
Un futuro che può essere esplicitamente completato (impostandone il valore e lo stato) e che può essere utilizzato come Fase di completamento, supportando funzioni e azioni dipendenti che si innescano al suo completamento.
Un esempio è riportato anche nell'elenco:
f.then((s -> aStringFunction(s)).thenAsync(s -> ...);
Si noti che l'API finale è leggermente diversa ma consente un'esecuzione asincrona simile:
CompletableFuture<String> f = ...;
f.thenApply(this::modifyString).thenAccept(System.out::println);
(Non sono completamente soddisfatto delle risposte finora, quindi ecco il mio tentativo ...)
Penso che il commento di Kevin Wright ( "Puoi fare una promessa e spetta a te mantenerla. Quando qualcun altro ti fa una promessa devi aspettare per vedere se lo onorano in futuro" ) lo riassume abbastanza bene, ma alcuni la spiegazione può essere utile.
Futuri e promesse sono concetti abbastanza simili, la differenza è che un futuro è un contenitore di sola lettura per un risultato che non esiste ancora, mentre una promessa può essere scritta (normalmente solo una volta). Java 8 CompletableFuture e Guava SettableFuture possono essere considerati promesse, perché il loro valore può essere impostato ("completato"), ma implementano anche l'interfaccia Future, quindi non c'è differenza per il client.
Il risultato del futuro sarà impostato da "qualcun altro" - dal risultato di un calcolo asincrono. Nota come FutureTask - un futuro classico - deve essere inizializzato con Callable o Runnable, non esiste un costruttore senza argomenti e sia Future che FutureTask sono di sola lettura dall'esterno (i metodi impostati di FutureTask sono protetti). Il valore verrà impostato sul risultato del calcolo dall'interno.
D'altra parte, il risultato di una promessa può essere impostato da "voi" (o di fatto da chiunque) in qualsiasi momento perché ha un metodo di impostazione pubblica. Sia CompletableFuture che SettableFuture possono essere creati senza alcuna attività e il loro valore può essere impostato in qualsiasi momento. Invia una promessa al codice cliente e adempia in seguito come desideri.
Si noti che CompletableFuture non è una promessa "pura", può essere inizializzata con un'attività proprio come FutureTask e la sua caratteristica più utile è il concatenamento non correlato delle fasi di elaborazione.
Si noti inoltre che una promessa non deve essere un sottotipo di futuro e non deve essere lo stesso oggetto. In Scala un oggetto Future viene creato da un calcolo asincrono o da un diverso oggetto Promise. In C ++ la situazione è simile: l'oggetto promessa viene utilizzato dal produttore e l'oggetto futuro dal consumatore. Il vantaggio di questa separazione è che il cliente non può impostare il valore del futuro.
Sia Spring che EJB 3.1 hanno una classe AsyncResult, che è simile alle promesse di Scala / C ++. AsyncResult implementa Future ma questo non è il vero futuro: i metodi asincroni in Spring / EJB restituiscono un oggetto Future diverso e di sola lettura attraverso un po 'di magia di fondo, e questo secondo "reale" futuro può essere utilizzato dal client per accedere al risultato.
Sono consapevole che esiste già una risposta accettata, ma vorrei aggiungere i miei due centesimi:
TLDR: Future e Promise sono i due lati di un'operazione asincrona: consumatore / chiamante vs. produttore / implementatore .
Come chiamante di un metodo API asincrono, otterrai Future
un handle per il risultato del calcolo. Ad esempio, è possibile chiamarlo get()
per attendere il completamento del calcolo e il recupero del risultato.
Ora pensa a come viene effettivamente implementato questo metodo API: l' implementatore deve restituire Future
immediatamente un . Sono responsabili del completamento di quel futuro non appena il calcolo sarà completato (cosa che sapranno perché sta implementando la logica di invio ;-)). Useranno un Promise
/ CompletableFuture
per fare proprio questo: costruisci e restituisci CompletableFuture
immediatamente e chiama complete(T result)
una volta fatto il calcolo.
Darò un esempio di ciò che è Promessa e di come il suo valore potrebbe essere impostato in qualsiasi momento, al contrario di Future, il cui valore è solo leggibile.
Supponi di avere una mamma e di chiederle soldi.
// 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);
Il risultato è:
Thank you mom for $10
La promessa della mamma è stata creata, ma ha aspettato qualche evento di "completamento".
CompletableFuture<Integer> promise...
Hai creato un evento del genere, accettando la sua promessa e annunciando i tuoi piani per ringraziare tua madre:
promise.thenAccept...
In questo momento la mamma ha iniziato ad aprire la borsa ... ma molto lentamente ...
e tuo padre ha interferito molto più velocemente e ha completato la promessa invece di tua madre:
promise.complete(10);
Hai notato un esecutore che ho scritto esplicitamente?
È interessante notare che se usi invece un esecutore implicito predefinito (commonPool) e il padre non è a casa, ma solo la mamma con la sua "borsa lenta", la sua promessa si completerà solo se il programma vive più a lungo di quanto la mamma abbia bisogno di ottenere soldi dal borsa.
L'esecutore predefinito si comporta come un "demone" e non aspetta che tutte le promesse vengano mantenute. Non ho trovato una buona descrizione di questo fatto ...
Non sono sicuro che questa possa essere una risposta, ma come vedo quello che gli altri hanno detto per qualcuno potrebbe sembrare che tu abbia bisogno di due astrazioni separate per entrambi questi concetti in modo che uno di essi ( Future
) sia solo una vista di sola lettura dell'altro ( Promise
) ... ma in realtà questo non è necessario.
Ad esempio, dai un'occhiata a come sono definite le promesse in javascript:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
L'attenzione si concentra sulla componibilità usando il then
metodo come:
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);
})
che rende il calcolo asincrono simile al sincrono:
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);
}
che è abbastanza bello. (Non fico come async-waitit ma async-wait rimuove solo la piastra della caldaia .... quindi (funzione (risultato) {.... da essa).
E in realtà la loro astrazione è abbastanza buona come il costruttore della promessa
new Promise( function(resolve, reject) { /* do it */ } );
consente di fornire due callback che possono essere utilizzati per completare Promise
correttamente o con un errore. In modo che solo il codice che costruisce il Promise
può completarlo e il codice che riceve un Promise
oggetto già costruito ha la vista di sola lettura.
Con l'ereditarietà si può ottenere quanto sopra se la risoluzione e il rifiuto sono metodi protetti.
CompletableFuture
potrebbe avere una certa somiglianza con un Promise
ma non è ancora unPromise
, perché il modo in cui è destinato a essere consumato è diverso: Promise
il risultato di un viene consumato chiamando then(function)
e la funzione viene eseguita nel contesto del produttore immediatamente dopo che il produttore chiama resolve
. Il Future
risultato di A viene consumato chiamando il get
che induce il thread consumer ad attendere fino a quando il thread del produttore ha generato il valore, quindi lo elabora nel consumer. Future
è intrinsecamente multithread, ma ...
Promise
con un solo thread (e in effetti è l'ambiente preciso per cui sono stati originariamente progettati: le applicazioni javascript generalmente hanno un solo thread, quindi non è possibile implementarlo Future
lì). Promise
è quindi molto più leggero ed efficiente di Future
, ma Future
può essere utile in situazioni che sono più complesse e richiedono la cooperazione tra thread che non possono essere facilmente organizzati usando Promise
s. Riassumendo: Promise
è un modello push, mentre Future
è un modello pull (cfr Iterable vs Observable)
XMLHttpRequest
). Non credo all'affermazione dell'efficienza, ti capita di avere delle cifre? +++ Detto questo, una spiegazione molto bella.
get
un irrisolto Future
implicherà necessariamente 2 cambi di contesto del thread, che almeno qualche anno fa avrebbe richiesto circa 50 di noi .
Per il codice client, Promise è per osservare o allegare la richiamata quando è disponibile un risultato, mentre Future deve attendere il risultato e quindi continuare. Teoricamente tutto ciò che è possibile fare con i futuri è ciò che si può fare con le promesse, ma a causa della differenza di stile, l'API risultante per le promesse in diverse lingue facilita il concatenamento.
Nessun metodo impostato nell'interfaccia futura, ottieni solo metodo, quindi è di sola lettura. Informazioni su CompletableFuture, questo articolo potrebbe essere utile. completablefuture
Promise
e spetta a te mantenerlo. Quando qualcun altro ti fa una promessa devi aspettare per vedere se lo onorano nelFuture