¿Cuál es la diferencia entre Future
y Promise
?
Ambos actúan como un marcador de posición para resultados futuros, pero ¿dónde está la principal diferencia?
¿Cuál es la diferencia entre Future
y Promise
?
Ambos actúan como un marcador de posición para resultados futuros, pero ¿dónde está la principal diferencia?
Respuestas:
Según esta discusión , Promise
finalmente se ha pedido CompletableFuture
su inclusión en Java 8, y su javadoc explica:
Un Futuro que puede completarse explícitamente (estableciendo su valor y estado), y puede usarse como un CompletionStage, apoyando funciones dependientes y acciones que se disparan al finalizar.
También se da un ejemplo en la lista:
f.then((s -> aStringFunction(s)).thenAsync(s -> ...);
Tenga en cuenta que la API final es ligeramente diferente pero permite una ejecución asincrónica similar:
CompletableFuture<String> f = ...;
f.thenApply(this::modifyString).thenAccept(System.out::println);
(No estoy completamente contento con las respuestas hasta ahora, así que aquí está mi intento ...)
Creo que el comentario de Kevin Wright ( "Puedes hacer una promesa y depende de ti cumplirla. Cuando alguien más te hace una promesa, debes esperar para ver si la cumplen en el futuro" ) lo resume bastante bien, pero algunos La explicación puede ser útil.
Los futuros y las promesas son conceptos bastante similares, la diferencia es que un futuro es un contenedor de solo lectura para un resultado que aún no existe, mientras que una promesa se puede escribir (normalmente solo una vez). El Java 8 CompletableFuture y el Guava SettableFuture pueden considerarse promesas, porque su valor se puede establecer ("completar"), pero también implementan la interfaz Future, por lo tanto, no hay diferencia para el cliente.
El resultado del futuro será establecido por "alguien más", por el resultado de un cálculo asincrónico. Observe cómo FutureTask , un futuro clásico, debe inicializarse con un Callable o Runnable, no hay un constructor sin argumentos, y Future y FutureTask son de solo lectura desde el exterior (los métodos establecidos de FutureTask están protegidos). El valor se establecerá en el resultado del cálculo desde el interior.
Por otro lado, el resultado de una promesa puede ser establecido por "usted" (o de hecho por cualquiera) en cualquier momento porque tiene un método de establecimiento público. Tanto CompletableFuture como SettableFuture se pueden crear sin ninguna tarea, y su valor se puede establecer en cualquier momento. Envía una promesa al código del cliente y la cumple más tarde como lo desee.
Tenga en cuenta que CompletableFuture no es una promesa "pura", puede inicializarse con una tarea como FutureTask, y su característica más útil es el encadenamiento no relacionado de los pasos de procesamiento.
También tenga en cuenta que una promesa no tiene que ser un subtipo de futuro y no tiene que ser el mismo objeto. En Scala, un objeto Futuro se crea mediante un cálculo asincrónico o mediante un objeto Promise diferente . En C ++, la situación es similar: el objeto de promesa es utilizado por el productor y el futuro por el consumidor. La ventaja de esta separación es que el cliente no puede establecer el valor del futuro.
Tanto Spring como EJB 3.1 tienen una clase AsyncResult, que es similar a las promesas de Scala / C ++. AsyncResult implementa Future pero este no es el futuro real: los métodos asincrónicos en Spring / EJB devuelven un objeto Future diferente de solo lectura a través de cierta magia de fondo, y el cliente puede usar este segundo futuro "real" para acceder al resultado.
Soy consciente de que ya hay una respuesta aceptada pero, sin embargo, me gustaría agregar mis dos centavos:
TLDR: Future y Promise son los dos lados de una operación asincrónica: consumidor / llamante versus productor / implementador .
Como llamador de un método API asíncrono, obtendrá Future
un control del resultado del cálculo. Puede, por ejemplo, invocarlo get()
para esperar a que se complete el cálculo y recuperar el resultado.
Ahora piense en cómo se implementa este método API: el implementador debe devolver un Future
inmediato. Son responsables de completar ese futuro tan pronto como se realice el cálculo (que sabrán porque está implementando la lógica de despacho ;-)). Utilizarán un Promise
/ CompletableFuture
para hacer exactamente eso: construir y devolver el CompletableFuture
inmediatamente, y llamar complete(T result)
una vez que se haya realizado el cálculo.
Daré un ejemplo de lo que es Promise y cómo se puede establecer su valor en cualquier momento, en oposición a Future, cuyo valor solo es legible.
Supongamos que tienes una madre y le pides dinero.
// 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);
La salida de eso es:
Thank you mom for $10
La promesa de mamá fue creada, pero esperó algún evento de "finalización".
CompletableFuture<Integer> promise...
Creaste tal evento, aceptando su promesa y anunciando tus planes para agradecer a tu madre:
promise.thenAccept...
En este momento, mamá comenzó a abrir su bolso ... pero muy lento ...
y el padre interfirió mucho más rápido y completó la promesa en lugar de su madre:
promise.complete(10);
¿Has notado un albacea que escribí explícitamente?
Curiosamente, si utiliza un ejecutor implícito predeterminado (commonPool) y el padre no está en casa, pero solo la madre con su "bolso lento", entonces su promesa solo se completará, si el programa dura más de lo que la madre necesita para obtener dinero del bolso.
El ejecutor predeterminado actúa como un "demonio" y no espera a que se cumplan todas las promesas. No he encontrado una buena descripción de este hecho ...
No estoy seguro de si esto puede ser una respuesta, pero como veo lo que otros han dicho sobre alguien, puede parecer que necesita dos abstracciones separadas para ambos conceptos, de modo que uno de ellos ( Future
) es solo una vista de solo lectura del otro ( Promise
) ... pero en realidad esto no es necesario.
Por ejemplo, eche un vistazo a cómo se definen las promesas en javascript:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
El enfoque está en la capacidad de compilación utilizando el then
método como:
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);
})
lo que hace que el cálculo asíncrono parezca síncrono:
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);
}
lo cual es genial (No es tan genial como async-await pero async-await simplemente elimina la repetitiva .... luego (función (resultado) {.... de ella).
Y en realidad su abstracción es bastante buena como constructor de promesas
new Promise( function(resolve, reject) { /* do it */ } );
le permite proporcionar dos devoluciones de llamada que se pueden utilizar para completar con Promise
éxito o con un error. De modo que solo el código que construye el Promise
puede completarlo y el código que recibe un Promise
objeto ya construido tiene la vista de solo lectura.
Con la herencia, se puede lograr lo anterior si resolver y rechazar son métodos protegidos.
CompletableFuture
puede tener alguna similitud con un Promise
pero todavía no es unPromise
, porque la forma en que se pretende consumir es diferente: Promise
el resultado de a se consume al llamar then(function)
, y la función se ejecuta en el contexto del productor inmediatamente después de que el productor llama resolve
. El Future
resultado de A se consume al llamar, lo get
que hace que el subproceso del consumidor espere hasta que el subproceso del productor haya generado el valor y luego lo procese en el consumidor. Future
es inherentemente multiproceso, pero ...
Promise
solo hilo (y de hecho, ese es el entorno preciso para el que fueron diseñados originalmente: las aplicaciones javascript generalmente solo tienen un solo hilo, por lo que no puede implementarlo Future
allí). Promise
es, por lo tanto, mucho más liviano y eficiente que Future
, pero Future
puede ser útil en situaciones que son más complejas y requieren cooperación entre hilos que no se pueden organizar fácilmente usando Promise
s. Para resumir: Promise
es un modelo push, mientras que Future
es un modelo pull (cf Iterable vs Observable)
XMLHttpRequest
). No creo en la afirmación de eficiencia, ¿tienes algunas cifras? +++ Dicho eso, una muy buena explicación.
get
a una resolución Future
no resuelta necesariamente implicará cambios de contexto de 2 hilos, que al menos unos años atrás probablemente requerirían alrededor de 50 de nosotros .
Para el código del cliente, Promise es para observar o adjuntar una devolución de llamada cuando hay un resultado disponible, mientras que Future es esperar el resultado y luego continuar. Teóricamente, cualquier cosa que sea posible hacer con futuros, lo que se puede hacer con promesas, pero debido a la diferencia de estilo, la API resultante para promesas en diferentes idiomas facilita el encadenamiento.
No hay un método establecido en la interfaz Future, solo obtiene un método, por lo que es de solo lectura. Sobre CompletableFuture, este artículo puede ser útil. futuro completo
Promise
y depende de usted mantenerlo. Cuando alguien más te hace una promesa, debes esperar para ver si la cumplen en elFuture