【问题标题】:Why do we need both Future and Promise?为什么我们需要 Future 和 Promise?
【发布时间】:2017-03-12 21:58:35
【问题描述】:

据我所知,Future 是只读的,Promise 是一次写入数据结构。

我们需要一个Promise 来完成一个Future

例如,

object Lie extends Throwable

val lie = Future { throw Lie } 

val guess = Promise[String]()     

lie.onComplete { case Success(s) => guess.success("I knew it was true!") 
                 case Failure(t) => guess.failure("I knew it was lie")} 
// return type: Unit 

guess.future.map(println) 
// res12: scala.concurrent.Future[Unit] = List()
// I knew it was lie!
// Requires Promise to chain Future with exception 


但是,我不明白为什么我们需要同时拥有 FuturePromise

我猜Promise 是必需的,因为Future.onComplete 签名

由于Future.onComplete 返回类型为UnitFuture 可能的异常不能被链接

我假设引入 Promise 是为了克服这个限制


但是为什么不直接更改 Future.onComplete 的签名呢?

Future.onComplete 的返回类型更改为Future[T] 将启用Future 上的链接,但有异常

然后,Future 不需要Promise

比如上面的代码可以改成

val lie = Future { throw Lie } 

lie.onComplete { 
   case Success(s) => "I knew it was true!"
   case Failure(t) => "I knew it was lie!"
}.map(println) 

//onComplete return type is Future[String]


我的问题是

1) 我说的对吗? Future 不需要Promise ,如果onComplete 签名从Unit 更改为Future[T]

2) 为什么 Future 和 Promise 首先是分开的?

UDPATE

感谢回复者,现在我明白了 Promise 的目的。它实际上不是用于Future 链接

如果可以,我可以问你吗

为什么onComplete 返回Unit ??

它实际上可以返回Future[T] 以轻松启用链接Future

例如

Future { throw Error }.onComplete {
  case Success(s) => "Success" 
  case Failure(t) => throw Error
}.onComplete {
  case Success(s) => "Success"
  case Failure(t) => throw Error 
}. ... 

【问题讨论】:

  • (关于您的更新);您可能想要 2.12 中新的 transform 方法,请参见此处:github.com/viktorklang/blog/blob/master/…(此“博客”中的其他文章也值得一读)
  • @Fabian 感谢 Fabian,这是对我最好的回答
  • 不幸的是,Java 8 的作者认为我们不需要将这两个概念分开(又名CompletableFuture)。

标签: scala jvm promise future


【解决方案1】:

Future.apply[T](block: => T): Future[T]Future.unit.map(_ => block)[1] 的语法糖

Future 代表一个,它可能当前可用也可能不可用。

Promise 表示有义务在某个时候提供这样的值。

Future(用于读取)和Promise(用于写入)拥有单独的实体意味着很容易推断功能:

  • 当 Future 是一个参数时,它是一个在某个时间点具有某个值的请求,当它用作返回类型时,它是一个当前可能不可用的响应.

  • 当 Promise 是一个参数时,它是在某个时刻产生某个值的责任的“消耗”,而当它用作返回类型时,它是产生该值的责任的“生产”在某个时候。

总而言之,能够推理能力,尤其是在异步甚至并发程序中,是非常有价值的。

大多数时候不需要使用 Promise,因为它由 Future-combinators 透明地处理,但在与第三方软件或网络库集成时,它可能非常有用。

有关 Scala 2.12 中有趣的新功能的更多信息,请查看here

1: 在哪里Future.unit 定义为: val unit: Future[Unit] = Future.successful(())

【讨论】:

  • 非常感谢。你的回答很有帮助!但是 Future.unit 是什么? api文档中没有解释
  • @wonpyoPark 这在脚注中有解释。有关更多信息,请查看我的回答中 scala 2.12 中更多新闻的链接。
【解决方案2】:

我说的对吗? Future 不需要 Promise ,如果 onComplete 签名是 从 Unit 更改为 Future[T]?

你把事情搞混了。让我们澄清一下。

Future[T] 表示将在未来完成的计算。也就是说,您向Future.apply 传递了一个函数,该函数将在您定义的某个ExecutionContext 分配的线程上执行。

另一方面,Promise[T] 是一种创建Future[T]的方法,而无需实际创建Future[T]。一个很好的例子是Future.successful 方法(它将在内部使用Promise.successful):

def successful[T](result: T): Future[T] = Promise.successful(result).future

这不需要ExecutionContext,也不需要排队(如果有任何其他资源)。它只是一个方便的包装器,可让您“人为”创建Future[T]

【讨论】:

  • 感谢您的解释,这有助于我更好地理解。
  • 有点好笑。 “这不需要 ExecutionContext,如果有任何额外的资源,也不需要排队。它只是一个方便的包装器,允许你“人为地”创建一个 Future[T]。”好吧,因为要生成result,您必须使用线程。现在,当它完成后,您将向我们展示如何使用冗余的 Promise API 来将 result 包装在已经完成的 Future 中。这绝不是同时拥有 Promise 和 Future API 的好理由。 Promise 可以保留为内部实现细节,但我认为没有任何理由将其暴露给开发人员。
  • @rapt 假设您有一些包含一些本机代码的代码。这个函数做了一些工作,也许是异步使用一些 C 线程,你想传递一些 void* 以在完成时调用(一些任意处理程序)。 Promise 将允许您将完成控制推迟到该代码,因为只有它知道操作何时完成。
  • @YuvalItzchakov 我不确定你的想法是否正确——我只是指 Scala 环境中的 OP 问题——但在我看来,你正在尝试做的事情可以(也)由Future.onComplete 完成。顺便说一句,我认为 Promise 本身不知道操作何时完成(onComplete),它只知道它是否已完成(isCompleted)。你给的 Promise 的定义很好。我认为更清晰的定义是:“Promise 是未来的工厂”。但令人困惑的是,Promise 经常由另一个 Future 完成(即更新)。
【解决方案3】:

没有。

Future不能涵盖Promise的用例。 Promise 有自己的价值。您不能将Future 替换为Promise

Future 表示稍后可用的计算。未来执行完成后,您可以使用onComplete 获得结果,您可以使用mapflatMaprecoverrecoverWith 组合期货。

Promise 是一次性写入容器,客户端可以订阅容器。当订阅的客户端获得未来等待,直到将值写入名为 promise 的容器中。

Future 是只读的

您不能将未来用作一次性写入容器。您只能从未来读取。

Promise 不同。

如果你想给用户一些你现在没有但你认为很快就会有的东西怎么办?

这意味着你向用户承诺你现在没有的东西。

因此,您希望让用户一直等待,直到您拥有要提供给用户的东西。那就是您执行p.future 并生成未来,以便用户可以使用未来等待结果。

一旦你得到了你承诺给用户的结果,你通过在发生不好的事情时将未来设为successfailure 来给用户(即通过p.complete)。

即使onComplete 返回类型更改为Future[T]Future 不能像Promise 那样行事或服务于Promise 的目的。

使用 Future 伴随对象创建未来

也可以使用Future.apply 来创建未来。在这种情况下,一旦 future 内部的计算完成,future created 就会完成。

Future 用于订阅耗时计算的结果,而 Promise 可以是发布和订阅模型。

【讨论】:

  • 感谢您的回答,您在我编辑后阅读了我的问题吗?你能更具体地回答我关于 onComplete 签名(返回类型)的问题吗
  • @WonpyoPark。即使onComplete 返回类型更改为Future[T]Future 不能像Promise 那样行事或服务于Promise 的目的。
  • 非常感谢!谢谢你,我明白了 Promise 的目的
  • @pamu 你没有解释你只能用 Promise 而不能用 Future 做什么。你似乎承诺会做出解释,但没有任何解释。
  • @rapt 现在添加了它。
猜你喜欢
  • 2016-03-14
  • 2021-08-23
  • 1970-01-01
  • 2019-06-09
  • 2020-09-05
  • 2012-12-03
  • 2016-06-25
  • 1970-01-01
  • 2014-06-18
相关资源
最近更新 更多