Future
和有什么区别Promise
?
它们都充当未来结果的占位符,但主要区别在哪里?
9 回答
(到目前为止,我对答案并不完全满意,所以这是我的尝试......)
我认为 凯文赖特的评论
你可以做出一个承诺,并由你来遵守它。当别人给你一个承诺时,你必须等待,看看他们是否在未来兑现它
总结得很好,但一些解释可能很有用。
Futures 和 Promise是非常相似的概念,不同之处在于 Future 是一个只读容器,用于存储尚不存在的结果,而 Promise 可以写入(通常只写一次)。Java 8 CompletableFuture和 Guava SettableFuture可以被认为是 Promise,因为它们的值可以设置(“完成”),但它们也实现了 Future 接口,因此对于客户端没有区别。
未来的结果将由“其他人”设置 - 由异步计算的结果。注意FutureTask - 一个经典的未来 -必须使用 Callable 或 Runnable 进行初始化,没有无参数的构造函数,Future 和 FutureTask 从外部都是只读的(FutureTask 的 set 方法受到保护)。该值将设置为从内部计算的结果。
另一方面,promise 的结果可以由“你”(或者实际上任何人)随时设置,因为它有一个公共的 setter 方法。CompletableFuture 和 SettableFuture 都可以在没有任何任务的情况下创建,并且可以随时设置它们的值。您向客户端代码发送一个承诺,并在以后如您所愿地履行它。
注意 CompletableFuture 不是一个“纯粹的”promise,它可以像 FutureTask 一样用任务初始化,它最有用的特性是处理步骤的不相关链接。
另请注意,promise 不必是 future 的子类型,也不必是同一个对象。在 Scala 中,Future 对象由异步计算或不同的Promise 对象创建。在 C++ 中情况类似:promise 对象由生产者使用,future 对象由消费者使用。这种分离的好处是客户端无法设置未来的价值。
Spring和EJB 3.1都有一个 AsyncResult 类,它类似于 Scala/C++ 承诺。AsyncResult 确实实现了 Future 但这不是真正的未来:Spring/EJB 中的异步方法通过一些背景魔法返回一个不同的只读 Future 对象,客户端可以使用第二个“真实”未来来访问结果。
根据这个讨论,Promise
终于被要求CompletableFuture
包含在 Java 8 中,它的 javadoc解释说:
可以显式完成的 Future(设置其值和状态),并且可以用作 CompletionStage,支持在其完成时触发的相关函数和操作。
列表中还给出了一个示例:
f.then((s -> aStringFunction(s)).thenAsync(s -> ...);
请注意,最终的 API 略有不同,但允许类似的异步执行:
CompletableFuture<String> f = ...;
f.thenApply(this::modifyString).thenAccept(System.out::println);
我知道已经有一个可以接受的答案,但还是想加两分钱:
TLDR:Future 和 Promise 是异步操作的两个方面:消费者/调用者与生产者/实现者。
作为异步 API 方法的调用者,您将获得 aFuture
作为计算结果的句柄。例如,您可以调用get()
它来等待计算完成并检索结果。
现在想想这个 API 方法是如何实际实现的:实现者必须立即返回 a Future
。他们负责在计算完成后立即完成那个未来(他们会知道,因为它正在实现调度逻辑;-))。他们将使用Promise
/CompletableFuture
来做到这一点:构造并立即返回,并在计算完成后CompletableFuture
调用。complete(T result)
我将举例说明什么是 Promise 以及如何在任何时候设置它的值,与 Future 相反,它的值是只读的。
假设你有一个妈妈,你向她要钱。
// 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);
的输出是:
Thank you mom for $10
妈妈的承诺已创建,但等待一些“完成”事件。
CompletableFuture<Integer> promise...
您创建了这样的活动,接受了她的承诺并宣布了您感谢妈妈的计划:
promise.thenAccept...
这时妈妈开始打开她的钱包……但是很慢……
父亲干预得更快,代替你妈妈完成了承诺:
promise.complete(10);
你有没有注意到我明确写的一个执行者?
有趣的是,如果您使用默认的隐式执行程序 (commonPool) 并且父亲不在家,而只有妈妈带着她的“慢钱包”,那么她的承诺只会完成,如果程序的寿命超过妈妈需要从钱包。
默认执行器的行为有点像“守护进程”,不会等待所有承诺都被履行。我还没有找到一个很好的描述这个事实......
不确定这是否可以成为答案,但正如我看到其他人对某人所说的那样,您可能需要对这两个概念进行两个单独的抽象,以便其中一个(Future
)只是另一个的只读视图(Promise
) ...但实际上这不是必需的。
例如看一下如何在 javascript 中定义 Promise:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
重点是使用以下then
方法的可组合性:
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);
})
这使得异步计算看起来像同步:
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);
}
这很酷。(不像async-await那样酷,但async-await只是删除了样板文件....then(function(result) {.... )。
实际上,它们的抽象作为 promise 构造函数非常好
new Promise( function(resolve, reject) { /* do it */ } );
允许您提供两个回调,可用于Promise
成功完成或出错。这样只有构造 的代码Promise
才能完成它并且接收已经构造的Promise
对象的代码具有只读视图。
如果resolve和reject是受保护的方法,则可以通过继承实现上述目标。
对于客户端代码,Promise 用于在结果可用时观察或附加回调,而 Future 是等待结果然后继续。理论上任何可以用期货做的事情都可以用 Promise 做,但是由于风格的不同,不同语言的 Promise 的 API 使得链接更容易。
Future接口中没有set方法,只有get方法,所以是只读的。关于 CompletableFuture,这篇文章可能会有所帮助。 可完成的未来
Future
并且Promise
是未知结果的代理对象
Promise
完成一个Future
Promise
- 未知结果的编写/生产者。Future
- 读取/使用未知结果。它有下一个状态:待处理、已完成、已取消
//Future has a reference to Promise
Future -> Promise
作为producer
我的promise
某事并为此负责
作为一个consumer
检索到 apromise
我希望在future
. 在future
我可以使用promise
或拒绝它
至于Java CompletableFutures
,它是Promise
因为你可以设置结果并且它也实现了Future
在这个示例中,您可以了解如何在 Java 中使用 Promises 来创建异步调用序列:
doSomeProcess()
.whenResult(result -> System.out.println(String.format("Result of some process is '%s'", result)))
.whenException(e -> System.out.println(String.format("Exception after some process is '%s'", e.getMessage())))
.map(String::toLowerCase)
.mapEx((result, e) -> e == null ? String.format("The mapped result is '%s'", result) : e.getMessage())
.whenResult(s -> System.out.println(s));