Future
和 Promise
之间有什么区别?
它们都充当未来结果的占位符,但主要区别在哪里?
Promise
,并由您自己决定是否保留它。当其他人向您做出承诺时,您必须等着看他们是否在 Future
(到目前为止,我对答案并不完全满意,所以这是我的尝试......)
你可以做出一个承诺,并由你来遵守它。当别人给你一个承诺时,你必须等待,看看他们是否在未来兑现它
总结得很好,但一些解释可能很有用。
Futures and promises 是非常相似的概念,不同之处在于 Future 是一个只读容器,用于存储尚不存在的结果,而 Promise 可以写入(通常只能写入一次)。 Java 8 CompletableFuture 和 Guava SettableFuture 可以被认为是 Promise,因为它们的值可以设置(“完成”),但它们也实现了 Future 接口,因此对于客户端没有区别。
未来的结果将由“其他人”设置 - 由异步计算的结果。请注意 FutureTask - 一个经典的未来 - 必须 使用 Callable 或 Runnable 进行初始化,没有无参数的构造函数,并且 Future 和 FutureTask 从外部都是只读的(set 方法的 FutureTask 受到保护)。该值将设置为从内部计算的结果。
另一方面,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 对象,客户端可以使用第二个“真实”未来来访问结果。
根据 this discussion,Promise
最终被称为 CompletableFuture
以包含在 Java 8 中,its 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 方法的调用者,您将获得一个 Future
作为计算结果的句柄。例如,您可以在其上调用 get()
以等待计算完成并检索结果。
现在想想这个 API 方法是如何实际实现的:implementor 必须立即返回一个 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 是受保护的方法,则可以通过继承实现上述目标。
CompletableFuture
可能与 Promise
有一些相似之处,但它仍然不是 Promise
,因为它的使用方式不同:使用 Promise
的结果通过调用 then(function)
,该函数在生产者调用 resolve
后立即执行在生产者的上下文中。 Future
的结果通过调用 get
来消耗,这导致消费者线程等待直到生产者线程生成值,然后在消费者中处理它。 Future
本质上是多线程的,但是...
Promise
(事实上,这正是它们最初设计的精确环境:javascript 应用程序通常只有一个线程,所以你不能 i> 在那里实现Future
)。因此,Promise
比 Future
更轻量级和更有效,但 Future
在更复杂的情况下很有帮助,并且需要线程之间的协作,而使用 { 1}秒。总结一下:Promise
是推送模型,而 Future
是拉取模型(参见 Iterable 与 Observable)
XMLHttpRequest
)。我不相信效率声称,你碰巧有一些数字吗? +++ 也就是说,一个非常好的解释。
Future
上调用 get
必然涉及 2 个线程上下文切换,至少几年前可能需要 around 50 us。
对于客户端代码,Promise 用于在结果可用时观察或附加回调,而 Future 是等待结果然后继续。理论上任何可以用期货做的事情都可以用 Promise 做,但是由于风格的不同,不同语言的 Promise 的 API 使得链接更容易。
Future
和 Promise
是未知结果的代理对象
Promise
完成 Future
Promise - 编写/产生未知结果。
未来 - 未知结果的读取/消费者。它有下一个状态:待处理、已完成、已取消
//Future has a reference to Promise
Future -> Promise
作为producer
我promise
某事并为此负责
作为检索 promise
的 consumer
,我希望在 future
中得到结果。在 future
我可以使用 promise
或拒绝它
至于 Java CompletableFutures
,它是一个 Promise
,因为您可以设置结果并且它还实现了 Future
在 this example 中,您可以了解如何在 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));
不定期副业成功案例分享