为什么Scala的Future没有.get / get(maxDuration)方法,迫使我们求助于Await.result()?

时间:2016-07-01 23:54:45

标签: scala future

get方法与Future类(我希望它驻留在哪里)解耦,是否有任何特别的优势,而是迫使编码人员必须知道这个外部的两个 - 方法类名为Await

3 个答案:

答案 0 :(得分:16)

  

Suite: Intrinsics ('intr'), hidden: yes Name: "Intrinsics", description: "" Class: item ('cobj'), superclass: <none>, hidden: no Implementation class: NSObject Name: "item", plural name: "items", description: "A scriptable object." Attribute: classCode ('pcls'), type: type ('type'), access: read-only, hidden: no Name: "class", description: "The class of the object." Attribute: scriptingProperties ('pALL'), type: record ('reco'), access: read-write, hidden: no Name: "properties", description: "All of the object's properties." Default subcontainer: <none> Supported command: delete, method: - Supported command: exists, method: - Supported command: set, method: - Supported command: get, method: - Supported command: count, method: - Supported command: move, method: - Supported command: duplicate, method: - Primitive type: <none> Command: get ('core'/'getd'), hidden: no Implementation class: NSGetCommand Name: "get", description: "Returns the value of the specified object(s)." Unnamed argument ('----'), type: specifier ('obj '), optional: no (No user-readable name or description needed for unnamed arguments) Result type: any ('****') Description: <none> Command: set ('core'/'setd'), hidden: no Implementation class: NSSetCommand Name: "set", description: "Sets the value of the specified object(s)." Unnamed argument ('----'), type: specifier ('obj '), optional: no (No user-readable name or description needed for unnamed arguments) Argument: Value ('data'), type: any ('****'), optional: no, hidden: no Name: "to", description: "The new value." Result type: <none> ('null') Description: <none> Value type: any ('****') Implementation class: NSAppleEventDescriptor Value type: boolean ('bool') Implementation class: NSNumber Value type: date ('ldt ') Implementation class: NSDate Value type: file ('file') Implementation class: NSURL Value type: integer ('long') Implementation class: NSNumber Value type: location specifier ('insl') Implementation class: NSPositionalSpecifier Value type: missing value ('msng') Implementation class: NSNull Value type: number ('nmbr') Implementation class: NSNumber Value type: point ('QDpt') Implementation class: NSData Value type: real ('doub') Implementation class: NSNumber Value type: record ('reco') Implementation class: NSDictionary Value type: rectangle ('qdrt') Implementation class: NSData Value type: specifier ('obj ') Implementation class: NSScriptObjectSpecifier Value type: text ('ctxt') Implementation class: NSString Value type: type ('type') Implementation class: NSNumber Object type: item ('cobj') Suite: HelloWorld ('HELO'), hidden: no Name: "HelloWorld", description: "HelloWorld scripting suite" Class: application ('capp'), superclass: item, hidden: no Implementation class: NSApplication Name: "application", plural name: "applications", description: "top-level scripting object" Attribute: property1 ('Hadp'), type: text ('ctxt'), access: read-only, hidden: no Name: "property1", description: "property1" Default subcontainer: <none> Primitive type: <none> Object type: application ('capp') 方法与get类解耦

是否有任何特别的优势

是的,让开发人员难以做错误的事情Future表示将在未来完成的计算,可能在当前调用点不可用。如果您需要阻止未来,为什么不同步执行它?什么是在线程池上安排它的重点,浪费了一个非常好的线程池线程?

documentation says

  

阻挡未来之外

     

如前所述,出于性能和防止死锁的缘故,强烈建议不要阻止未来。期货的回调和组合者是使用其结果的首选方式。但是,在某些情况下可能需要阻止,并且Futures and Promises API支持阻止。

甚至是Await object documentation

  

虽然偶尔有用,例如对于测试,建议您尽可能避免使用Await支持回调和组合,如onComplete并用于理解。 Await将阻止它运行的线程,并可能导致性能和死锁问题。

你可以看到语言设计者故意想要这种效果。

答案 1 :(得分:16)

在接受的答案中提供更多历史 1

当我们在Scala生态系统中正式确定大量的Future实现时,我们想确保 2 我们没有标准化已知会产生问题的方法。

  

Future代表一个值(或无法产生所述值)   离婚了。

更具体地说,Future[T]的信息严格少于简单T,如下所示:

//At the line of this comment, there is no `f`
val f: Future[T] = … //At the line of this comment, there is an `f` but not necessarily its value of type `T`.

鉴于:

//At the line of this comment, there is no `t`
val t: T = … //At the line of this comment, there is a `T`

为什么这很重要,我听到你说。 好吧,如果你想要一个从Future[T]T的方法,你会说:我收到一个可能无法获得的值,我会在它之后返回。

这意味着该方法在值尚未可用时必须“传递时间”,这通常需要阻塞当前执行线程,并且由于执行线程是一个昂贵的资源,通常需要时间进入阻塞状态并再次返回 3 ,这是应该避免的。

好像这还不够,很容易陷入Futures无法完成的死锁,因为他们不会让线程执行,因为所有这些线程都试图获取那个未来的价值。

此外,我们意识到,只要Future实现有一个«blocking get»操作,许多用户会调用它而不会意识到它会对程序产生什么影响,直到它在生产中产生问题,因为它看起来很简单,但它的成本无处可见,直到为时已晚。

因此我们决定推广不需要阻塞的编程风格,例如回调 4 和转换 5 ,以降低死锁风险和性能不佳。

我们认为,如果我们完全忽略阻止从Future获得结果的能力,最终结果将是每个人都会重新发明它,并且可能具有不同的质量。

我们还发现,如果我们能够等待具体的thing,我们就会获得以下好处:

  • 所有Awaitable
  • 的API看起来都一样
  • 的代码审核很容易
  • 使用工具
  • 很容易禁止/允许
  • 我们可以使用blocking的概念来尝试执行规避动作以缓解死锁,在运行时禁止它,记录它,计时等等。

所以你有它!

干杯, √

1 自此成为SIP-14“期货与承诺”的共同创始人及其维护者。

2 确保您在API方面做到这一点......

3 线程唤醒延迟可以有效地将处理限制在1k-10kops / s之间。

4 我们也越来越不再强调使用回调,而是推广使用转换组合器,请参阅我为Scala 2.12 Futures写的this博客系列。

5 Ex。 mapflatMapfilterrecoverrecoverWith以及最近transformtransformWith

答案 2 :(得分:2)

登上期货

自Scala标准库中的第一个实现以来,在Futures上提供了.get。 虽然有些隐藏:.value.get

scala> val f = Future("test")
f: scala.concurrent.Future[String] = Success(test)

scala> f.value.get
res5: scala.util.Try[String] = Success(test)

使用它的缺点是,如果未来尚未返回,它将抛出异常。

scala> Future("test").value.get
res7: scala.util.Try[String] = Success(test)

scala> Future("test").value.get
 java.util.NoSuchElementException: None.get
 at scala.None$.get(Option.scala:347)
 at scala.None$.get(Option.scala:345)
 ... 32 elided

为什么Await.result而不是get(timeToWait)

添加@ YuvalsItzchakov的优秀答案: 使用Future i来使异步性在类型系统中可见的想法和所有编码器都表明使用这个概念的特殊规则适用并需要谨慎。 由于它是一个Applicative Functor,您可以使用mapforeach以及使用map和{{1}链接它们的方法,这是一种非常直接的方法来处理这些值。 }。

唯一没有内置意图的是如何&#34;未开发&#34;一个flatMap,同时保持特殊的时间相关的可配置等待规则。 这将粗略地描述Future会做什么。