【问题标题】:How to wait for result of Scala Futures in for comprehension如何在理解中等待 Scala Futures 的结果
【发布时间】:2016-04-29 08:12:47
【问题描述】:

我对以下代码有疑问。我希望在所有 groundCoffee、heaterWater、frothedMilk 方法完成后触发“combine”方法。它们将同时触发。所有 4 种方法磨碎、加热水、泡沫牛奶、冲泡都是使用未来同时执行的。

def prepareCappuccino(): Future[Cappuccino] = {
  val groundCoffee = grind("arabica beans")
  val heatedWater = heatWater(Water(20))
  val frothedMilk = frothMilk("milk")
  for {
    ground <- groundCoffee
    water <- heatedWater
    foam <- frothedMilk
    espresso <- brew(ground, water)
  } yield combine(espresso, foam)
}

当我执行上述方法时,我得到的输出如下

start grinding...
heating the water now
milk frothing system engaged!

然后程序退出。当我试图学习期货时,我从一个网站上得到了这个例子。如何让程序等待,以便在所有期货返回后触发组合方法?

【问题讨论】:

  • 感谢 @om-nom-nom 帮助格式化
  • 您可以只输入 Thread.sleep(duration) 或使用 scala.concurrent 包中的 Await
  • 是的,我可以这样做。当我使用断点时,程序按预期完成。但这不是我想要的。有没有其他方法可以在没有程序退出的情况下执行 combine 方法?希望我不会混淆太多
  • 我刚刚给了你解决方案。 import scala.concurrent.duration._ scala.concurrent.Await.ready(prepareCappuccino, 5.seconds)

标签: scala for-loop for-comprehension


【解决方案1】:

已经发布到Await 的解决方案是当您想要故意阻止该线程上的执行时的解决方案。这样做的两个常见原因是为了进行测试,当您想在做​​出断言之前等待结果时,以及当所有线程都将退出时(就像在做玩具示例时一样)。

但是,在适当的长寿命应用程序中,Await 通常应避免使用。

您的问题已经包含了一种正确的方式来进行未来的组合 - 使用 for 理解。请记住,for-comprehensions 将转换为 flatMaps、maps 和 withFilter 操作,因此您在 for-comprehension 中调用的任何期货都只会在其他期货完成后创建,即串行。

如果你想让一堆future同时运行,那么你可以在进入for-comprehension之前创建它们。

【讨论】:

  • 没错@monkjack。但是当我尝试运行示例组合方法时,永远不会调用这不是我想要的。实际上,我正在模拟它以匹配服务器启动期间的缓存加载系统,其中缓存应该同时加载以节省时间。因此,如果在缓存加载时传入线程,它应该等到缓存对象被加载。所以我觉得 Await.ready 是实现它的好方法。如果我错了,请纠正我
  • 您遇到的情况可能是因为您的程序正在退出。至于您的问题的一个很好的解决方案,即延迟请求直到达到某个状态,请发布另一个包含具体细节的问题。
【解决方案2】:

您可以在这里使用等待:

val f = Future.sequence(futures.toList)
Await.ready(f, Duration.Inf)

我假设,您已将所有期货打包在一个列表中。 Await.ready 完成所有等待工作。

【讨论】:

  • 我做到了,它奏效了。但是个别期货的 onSuccess 功能没有被触发。有办法吗?
  • @mavrav,如果您使用 map 而不是 onSuccessAwait 生成的未来,您将获得所需的行为。
猜你喜欢
  • 1970-01-01
  • 2013-02-09
  • 1970-01-01
  • 2017-03-27
  • 2011-08-08
  • 1970-01-01
  • 2015-07-14
  • 1970-01-01
  • 2016-11-24
相关资源
最近更新 更多