java - springlayout - Diferencia entre el futuro y la promesa
springlayout ejemplo (7)
(No estoy del todo 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 mantenerla. Cuando alguien más te hace una promesa debes esperar para ver si la honran 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 Futuro, por lo tanto, no hay diferencia para el cliente.
El resultado del futuro será establecido por "otra persona", 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 tanto Future como 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 cualquier persona) 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 puede establecerse en cualquier momento. Envía una promesa al código del cliente y lo completa más tarde como lo desee.
Tenga en cuenta que CompletableFuture no es una promesa "pura", se puede inicializar 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 Future 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 objeto 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 magia de fondo, y este segundo futuro "real" puede ser utilizado por el cliente para acceder al resultado.
¿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 diferencia principal?
Daré un ejemplo de lo que es Promesa y cómo se puede establecer su valor en cualquier momento, en oposición a Futuro, cuyo valor solo es legible.
Supongamos que tienes una madre y le pides dinero.
Ahora, engañas a tu madre para que te haga una promesa de una eventual donación, ella te da ese objeto de promesa, pero ella todavía no está realmente dispuesta a cumplirlo:
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);
Eres feliz, corres para agradecerle a tu madre:
promise.thenAccept(u->System.out.println("Thank you mom for $" + u ));
Pero tu padre interfiere y generalmente aborta los planes de la madre y cumple la promesa (¡establece su valor!) Con una contribución mucho menor, como hacen los padres, muy resueltamente, mientras mamá abre lentamente su bolso (fíjate 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...
Usted creó tal evento, aceptando su promesa y anunciando sus planes para agradecer a su madre:
promise.thenAccept...
En este momento mamá comenzó a abrir su bolso ... pero muy lento ...
y el padre intervino mucho más rápido y completó la promesa en lugar de su madre:
promise.complete(10);
¿Has notado a un ejecutor que escribí explícitamente? Es interesante que si usa el ejecutor implícito predeterminado (commonPool) y el padre no está en casa, solo la madre con su "bolso lento", entonces su promesa solo se completará, si el programa vive más tiempo del que mamá necesita para obtener dinero de la bolsa. Quiero decir que el ejecutor predeterminado actúa de una manera de "daemon". No he encontrado una buena descripción de este hecho ...
No estoy seguro si esto puede ser una respuesta, pero cuando veo lo que otros han dicho para 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, mira cómo se definen las promesas en javascript:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
El foco está en la capacidad de compilación usando el método then
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);
})
que hace que el cálculo asincrónico se vea como sincrónico:
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 tan genial como async-await pero async-await simplemente elimina la repetición ... luego (función (resultado) {.... de ella).
Y en realidad su abstracción es bastante buena como el constructor de la promesa
new Promise( function(resolve, reject) { /* do it */ } );
le permite proporcionar dos devoluciones de llamada que pueden usarse para completar la Promise
exitosamente o con un error. Para que solo el código que construye la Promise
pueda completarlo y el código que recibe un objeto Promise
ya construido tenga la vista de solo lectura.
Con la herencia, lo anterior se puede lograr si la resolución y el rechazo son métodos protegidos.
No hay un método establecido en la interfaz Futuro, solo obtiene el método, por lo que es de solo lectura. Acerca de CompletableFuture, este artículo puede ser útil. completablefuture
Para el código de cliente, Promise es para observar o adjuntar una devolución de llamada cuando hay un resultado disponible, mientras que Future espera el resultado y luego continúa. Teóricamente, cualquier cosa que se pueda 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.
Según esta discusión , Promise
finalmente se ha llamado CompletableFuture
para su inclusión en Java 8, y su javadoc explica:
Un Futuro que puede completarse explícitamente (establecer su valor y estado), y puede usarse como un CompletionStage, que admite funciones dependientes y acciones que se desencadenan al completarse.
Un ejemplo también se da 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);
Soy consciente de que ya hay una respuesta aceptada pero me gustaría agregar mis dos centavos:
Como llamador de un método API asíncrono, obtendrá un Future
como manejador del resultado del cálculo. Puede, por ejemplo, llamar a get()
para esperar a que se complete el cálculo y recuperar el resultado.
Ahora piense en cómo se implementa realmente este método API: el implementador debe devolver un Future
inmediatamente. Ella es responsable de completar ese futuro tan pronto como se realice el cálculo (que ella sabrá porque está implementando la lógica de despacho ;-)). Ella usará un Promise
/ CompletableFuture
para hacer justamente eso: Construya y devuelva el CompletableFuture
inmediato, y llame al complete(T result)
una vez que el cálculo haya finalizado.
TLDR: futuro y promesa son los dos lados de una operación asincrónica: consumidor / llamante vs. productor / implementador .