331

Future和有什么区别Promise
它们都充当未来结果的占位符,但主要区别在哪里?

4

9 回答 9

179

(到目前为止,我对答案并不完全满意,所以这是我的尝试......)

我认为 凯文赖特的评论

你可以做出一个承诺,并由你来遵守它。当别人给你一个承诺时,你必须等待,看看他们是否在未来兑现它

总结得很好,但一些解释可能很有用。

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 对象由消费者使用。这种分离的好处是客户端无法设置未来的价值。

SpringEJB 3.1都有一个 AsyncResult 类,它类似于 Scala/C++ 承诺。AsyncResult 确实实现了 Future 但这不是真正的未来:Spring/EJB 中的异步方法通过一些背景魔法返回一个不同的只读 Future 对象,客户端可以使用第二个“真实”未来来访问结果。

于 2015-03-02T23:01:02.920 回答
156

根据这个讨论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);
于 2013-01-26T22:07:05.373 回答
145

我知道已经有一个可以接受的答案,但还是想加两分钱:

TLDR:Future 和 Promise 是异步操作的两个方面:消费者/调用者生产者/实现者。

作为异步 API 方法的调用者,您将获得 aFuture作为计算结果的句柄。例如,您可以调用get()它来等待计算完成并检索结果。

现在想想这个 API 方法是如何实际实现的:实现者必须立即返回 a Future。他们负责在计算完成后立即完成那个未来(他们会知道,因为它正在实现调度逻辑;-))。他们将使用Promise/CompletableFuture来做到这一点:构造并立即返回,并在计算完成后CompletableFuture调用。complete(T result)

于 2015-01-06T07:17:09.553 回答
109

我将举例说明什么是 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) 并且父亲不在家,而只有妈妈带着她的“慢钱包”,那么她的承诺只会完成,如果程序的寿命超过妈妈需要从钱包。

默认执行器的行为有点像“守护进程”,不会等待所有承诺都被履行。我还没有找到一个很好的描述这个事实......

于 2017-02-01T05:55:24.970 回答
10

不确定这是否可以成为答案,但正如我看到其他人对某人所说的那样,您可能需要对这两个概念进行两个单独的抽象,以便其中一个(Future)只是另一个的只读视图(Promise) ...但实际上这不是必需的。

例如看一下如何在 javascript 中定义 Promise:

https://promisesaplus.com/

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对象的代码具有只读视图。

如果resolvereject是受保护的方法,则可以通过继承实现上述目标。

于 2016-05-27T07:37:52.920 回答
5

对于客户端代码,Promise 用于在结果可用时观察或附加回调,而 Future 是等待结果然后继续。理论上任何可以用期货做的事情都可以用 Promise 做,但是由于风格的不同,不同语言的 Promise 的 API 使得链接更容易。

于 2017-11-25T18:10:38.113 回答
2

Future接口中没有set方法,只有get方法,所以是只读的。关于 CompletableFuture,这篇文章可能会有所帮助。 可完成的未来

于 2017-09-06T17:33:43.893 回答
1

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

于 2021-02-06T21:58:53.500 回答
0

这个示例中,您可以了解如何在 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));
于 2020-07-02T12:51:37.493 回答