Qual é a diferença entre Future
e Promise
?
Ambos agem como um espaço reservado para resultados futuros, mas qual é a principal diferença?
Qual é a diferença entre Future
e Promise
?
Ambos agem como um espaço reservado para resultados futuros, mas qual é a principal diferença?
Respostas:
De acordo com essa discussão , Promise
finalmente foi chamado CompletableFuture
para inclusão no Java 8 e seu javadoc explica:
Um futuro que pode ser explicitamente concluído (definindo seu valor e status) e pode ser usado como um CompletionStage, suportando funções e ações dependentes que são acionadas após sua conclusão.
Um exemplo também é dado na lista:
f.then((s -> aStringFunction(s)).thenAsync(s -> ...);
Observe que a API final é um pouco diferente, mas permite execução assíncrona semelhante:
CompletableFuture<String> f = ...;
f.thenApply(this::modifyString).thenAccept(System.out::println);
(Eu não estou completamente feliz com as respostas até agora, então aqui está minha tentativa ...)
Acho que o comentário de Kevin Wright ( "Você pode fazer uma promessa e depende de você cumpri-la. Quando alguém lhe faz uma promessa, você deve esperar para ver se a honrará no futuro" ) resume muito bem, mas alguns explicação pode ser útil.
Futuros e promessas são conceitos bastante semelhantes, a diferença é que o futuro é um contêiner somente leitura para um resultado que ainda não existe, enquanto uma promessa pode ser escrita (normalmente apenas uma vez). O Java 8 CompletableFuture e o Guava SettableFuture podem ser considerados promissores, porque seu valor pode ser definido ("concluído"), mas eles também implementam a interface Future, portanto, não há diferença para o cliente.
O resultado do futuro será definido por "outra pessoa" - pelo resultado de uma computação assíncrona. Observe como o FutureTask - um futuro clássico - deve ser inicializado com um Callable ou Runnable, não há construtor sem argumentos e o Future e o FutureTask são somente leitura de fora (os métodos definidos do FutureTask estão protegidos). O valor será definido como o resultado da computação a partir do interior.
Por outro lado, o resultado de uma promessa pode ser definido por "você" (ou, de fato, por qualquer pessoa) a qualquer momento, porque possui um método público de configuração. CompletableFuture e SettableFuture podem ser criados sem qualquer tarefa e seu valor pode ser definido a qualquer momento. Você envia uma promessa ao código do cliente e a cumpre mais tarde, conforme desejar.
Observe que CompletableFuture não é uma promessa "pura", pode ser inicializada com uma tarefa como a FutureTask, e seu recurso mais útil é o encadeamento não relacionado das etapas de processamento.
Observe também que uma promessa não precisa ser um subtipo de futuro e não precisa ser o mesmo objeto. No Scala, um objeto Futuro é criado por uma computação assíncrona ou por um objeto Promise diferente . Em C ++, a situação é semelhante: o objeto de promessa é usado pelo produtor e o objeto futuro pelo consumidor. A vantagem dessa separação é que o cliente não pode definir o valor do futuro.
O Spring e o EJB 3.1 têm uma classe AsyncResult, que é semelhante às promessas do Scala / C ++. O AsyncResult implementa Future, mas este não é o futuro real: métodos assíncronos no Spring / EJB retornam um objeto Future diferente, somente leitura, através de alguma mágica de fundo, e esse segundo futuro "real" pode ser usado pelo cliente para acessar o resultado.
Estou ciente de que já existe uma resposta aceita, mas gostaria de acrescentar meus dois centavos:
TLDR: Futuro e Promessa são os dois lados de uma operação assíncrona: consumidor / chamador vs. produtor / implementador .
Como chamador de um método de API assíncrono, você receberá Future
um identificador para o resultado da computação. Você pode, por exemplo, solicitar get()
que o cálculo seja concluído e recuperar o resultado.
Agora pense em como esse método de API é realmente implementado: O implementador deve retornar um Future
imediatamente. Eles são responsáveis por concluir esse futuro assim que o cálculo for concluído (o que eles saberão porque está implementando a lógica de despacho ;-)). Eles usarão um Promise
/ CompletableFuture
para fazer exatamente isso: Construa e retorne o CompletableFuture
imediatamente, e chame complete(T result)
assim que o cálculo estiver concluído.
Vou dar um exemplo do que é Promise e como seu valor pode ser definido a qualquer momento, ao contrário de Future, cujo valor é apenas legível.
Suponha que você tenha uma mãe e peça dinheiro a ela.
// 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);
Saída disso é:
Thank you mom for $10
A promessa da mamãe foi criada, mas esperou por algum evento de "conclusão".
CompletableFuture<Integer> promise...
Você criou esse evento, aceitando a promessa dela e anunciando seus planos de agradecer à sua mãe:
promise.thenAccept...
Nesse momento a mãe começou a abrir a bolsa ... mas muito devagar ...
e pai interferiram muito mais rápido e cumpriram a promessa em vez de sua mãe:
promise.complete(10);
Você notou um executor que eu escrevi explicitamente?
Curiosamente, se você usar um executor implícito padrão (commonPool) e o pai não estiver em casa, mas apenas a mãe com sua "bolsa lenta", sua promessa só será concluída se o programa viver mais do que a mãe precisa obter dinheiro com o Bolsa.
O executor padrão age como um "daemon" e não espera que todas as promessas sejam cumpridas. Não encontrei uma boa descrição desse fato ...
Não tenho certeza se isso pode ser uma resposta, mas como vejo o que os outros disseram para alguém, pode parecer que você precise de duas abstrações separadas para esses dois conceitos, de modo que um deles ( Future
) seja apenas uma visualização somente leitura do outro ( Promise
) ... mas, na verdade, isso não é necessário.
Por exemplo, veja como as promessas são definidas em javascript:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
O foco está na composibilidade usando o 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);
})
que faz com que a computação assíncrona pareça síncrona:
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);
}
o que é bem legal. (Não é tão legal quanto o assíncrono-aguardar, mas o assíncrono-aguarda apenas remove o clichê ... então (function (result) {.... dele).
E, na verdade, sua abstração é muito boa como construtora de promessas
new Promise( function(resolve, reject) { /* do it */ } );
permite fornecer dois retornos de chamada que podem ser usados para concluir com Promise
êxito ou com um erro. Para que apenas o código que constrói o Promise
possa concluí-lo e o código que recebe um Promise
objeto já construído tenha a exibição somente leitura.
Com a herança, o acima pode ser alcançado se resolver e rejeitar forem métodos protegidos.
CompletableFuture
pode ter alguma semelhança com a, Promise
mas ainda não éPromise
, porque a maneira como se destina a ser consumida é diferente: Promise
o resultado de a é consumido pela chamada then(function)
e a função é executada no contexto do produtor imediatamente após a ligação do produtor. resolve
. O Future
resultado de A é consumido pela chamada, get
que faz com que o encadeamento do consumidor aguarde até que o encadeamento do produtor gere o valor e o processe no consumidor. Future
é inerentemente multithreaded, mas ...
Promise
com apenas um thread (e, de fato, esse é o ambiente preciso para o qual foram projetados originalmente: aplicativos javascript geralmente têm apenas um thread, portanto você não pode implementá Future
-lo). Promise
é, portanto, muito mais leve e eficiente do que Future
, mas Future
pode ser útil em situações mais complexas e que exijam cooperação entre encadeamentos que não podem ser facilmente organizados usando Promise
s. Para resumir: Promise
é um modelo de impulso, enquanto que Future
é um modelo de recepção (cf Iterable vs observável)
XMLHttpRequest
). Eu não acredito na alegação de eficiência, você tem alguns números? +++ Dito isto, uma explicação muito boa.
get
de uma solução Future
não resolvida envolverá necessariamente duas alternâncias de contexto de encadeamento, que pelo menos alguns anos atrás provavelmente exigiriam cerca de 50 nós .
Para o código do cliente, o Promise é para observar ou anexar retorno de chamada quando um resultado estiver disponível, enquanto Futuro é aguardar pelo resultado e continuar. Teoricamente, tudo o que é possível fazer com os futuros pode ser feito com promessas, mas devido à diferença de estilo, a API resultante de promessas em diferentes idiomas facilita o encadeamento.
Nenhum método definido na interface Futuro, apenas o método get, portanto, é somente leitura. Sobre o CompletableFuture, este artigo pode ser útil. completablefuture
Promise
e depende de você mantê-lo. Quando alguém lhe faz uma promessa que você deve esperar para ver se eles honrá-lo noFuture