La promessa e il futuro sono concetti complementari. Il futuro è un valore che verrà recuperato, beh, in futuro e puoi fare cose con esso quando si verifica quell'evento. È quindi il punto finale di lettura o di uscita di un calcolo: è qualcosa da cui si recupera un valore.
A Promise è, per analogia, il lato scritto del calcolo. Crei una promessa che è il luogo in cui metti il risultato del calcolo e da quella promessa ottieni un futuro che verrà utilizzato per leggere il risultato che è stato inserito nella promessa. Quando completerai una Promessa, per fallimento o successo, attiverai tutto il comportamento che era associato al Futuro associato.
Per quanto riguarda la tua prima domanda, come può essere che per una promessa p che abbiamo p.future == p
. Puoi immaginarlo come un buffer di un singolo elemento: un contenitore inizialmente vuoto e successivamente puoi memorizzare un valore che diventerà il suo contenuto per sempre. Ora, a seconda del tuo punto di vista, questa è sia una promessa che un futuro. È una promessa per qualcuno che intende scrivere il valore nel buffer. È un futuro per qualcuno che aspetta che quel valore venga messo nel buffer.
In particolare, per l'API simultanea di Scala, se dai un'occhiata al tratto Promise qui puoi vedere come sono implementati i metodi dall'oggetto companion Promise:
object Promise {
/** Creates a promise object which can be completed with a value.
*
* @tparam T the type of the value in the promise
* @return the newly created `Promise` object
*/
def apply[T](): Promise[T] = new impl.Promise.DefaultPromise[T]()
/** Creates an already completed Promise with the specified exception.
*
* @tparam T the type of the value in the promise
* @return the newly created `Promise` object
*/
def failed[T](exception: Throwable): Promise[T] = new impl.Promise.KeptPromise[T](Failure(exception))
/** Creates an already completed Promise with the specified result.
*
* @tparam T the type of the value in the promise
* @return the newly created `Promise` object
*/
def successful[T](result: T): Promise[T] = new impl.Promise.KeptPromise[T](Success(result))
}
Ora, quelle implementazioni delle promesse, DefaultPromise e KeptPromise possono essere trovate qui . Entrambi estendono un piccolo tratto di base che sembra avere lo stesso nome, ma si trova in un pacchetto diverso:
private[concurrent] trait Promise[T] extends scala.concurrent.Promise[T] with scala.concurrent.Future[T] {
def future: this.type = this
}
Quindi puoi vedere cosa intendono p.future == p
.
DefaultPromise
è il buffer a cui mi riferivo sopra, mentre KeptPromise
è un buffer con il valore inserito dalla sua stessa creazione.
Per quanto riguarda il tuo esempio, il blocco futuro che usi lì crea effettivamente una promessa dietro le quinte. Diamo un'occhiata alla definizione di future
a qui :
def future[T](body: =>T)(implicit execctx: ExecutionContext): Future[T] = Future[T](body)
Seguendo la catena dei metodi si finisce nel Futuro impl .
private[concurrent] object Future {
class PromiseCompletingRunnable[T](body: => T) extends Runnable {
val promise = new Promise.DefaultPromise[T]()
override def run() = {
promise complete {
try Success(body) catch { case NonFatal(e) => Failure(e) }
}
}
}
def apply[T](body: =>T)(implicit executor: ExecutionContext): scala.concurrent.Future[T] = {
val runnable = new PromiseCompletingRunnable(body)
executor.execute(runnable)
runnable.promise.future
}
}
Quindi, come puoi vedere, il risultato che ottieni dal tuo blocco produttore viene riversato in una promessa.
MODIFICA SUCCESSIVA :
Per quanto riguarda l'uso nel mondo reale: la maggior parte delle volte non gestirai direttamente le promesse. Se utilizzerai una libreria che esegue calcoli asincroni, lavorerai solo con i futures restituiti dai metodi della libreria. Le promesse sono, in questo caso, create dalla libreria: stai solo lavorando con la fine della lettura di ciò che fanno questi metodi.
Ma se hai bisogno di implementare la tua API asincrona dovrai iniziare a lavorare con loro. Supponiamo di dover implementare un client HTTP asincrono sopra, diciamo, Netty. Quindi il tuo codice avrà un aspetto simile a questo
def makeHTTPCall(request: Request): Future[Response] = {
val p = Promise[Response]
registerOnCompleteCallback(buffer => {
val response = makeResponse(buffer)
p success response
})
p.future
}