Scala Future monod 中的 onComplete 方法

Posted

技术标签:

【中文标题】Scala Future monod 中的 onComplete 方法【英文标题】:onComplete method in Scala's Fututre monod 【发布时间】:2021-05-30 16:40:27 【问题描述】:

我正在学习 Scala 中的 Future 并拥有以下代码 sn-p。我正在根据名称中的第一个字母生成随机标记。 对于以下场景,我希望通过onComplete 方法打印一个列表。但它不打印任何东西。

def randomMark(name:String) = name(0) match 
  case 'R'|'A'|'J'|'S' => Thread.sleep(500); 99
  case  _              => Thread.sleep(500); 80


import scala.concurrent._
import concurrent.ExecutionContext.Implicits.global

val returns = Future sequence List( Future(randomMark("Rob")), Future(randomMark("Andy")), Future(randomMark("George")) )
    
Thread.sleep(550)

returns onComplete  e =>  val y1 = e.getOrElse("Error"); println(y1)      
//This println statement does not execute. I expect a list List(99,99,80) to be printed

有人可以帮我理解为什么我为onComplete 方法提供的功能文字不执行吗?

谢谢!

【问题讨论】:

如果这是一个完整的程序,那么它会直接退出而不等待未来完成。尝试添加Await.ready(returns, Duration.Inf) 【参考方案1】:

很可能是因为您需要等待结果,因为onComplete 是一个异步操作。

import scala.concurrent.duration._
import scala.concurrent._

def randomMark(name:String) = name(0) match 
  case 'R'|'A'|'J'|'S' => Thread.sleep(500); 99
  case  _              => Thread.sleep(500); 80


import scala.concurrent._
import concurrent.ExecutionContext.Implicits.global

val returns = Future sequence List( Future(randomMark("Rob")), Future(randomMark("Andy")), Future(randomMark("George")) )
    
Thread.sleep(550)

returns onComplete  e =>  val y1 = e.getOrElse("Error"); println(y1)     
println("Waiting futures to be completed")
Await.ready(returns, 5.seconds)
println("Futures to be completed")

打印出来了:

Waiting futures to be completed
List(99, 99, 80)
Futures to be completed

斯卡蒂:https://scastie.scala-lang.org/SWv18p8RTtuo7nMNHNHMoQ

【讨论】:

谢谢伊万!当我交换程序中的最后两个语句时,我得到了预期的结果。感谢您的宝贵时间。【参考方案2】:

由于回调是异步执行的,因此您需要在程序退出之前等待回调完成。在这种情况下,如果你想等待一个 onComplete 回调,你需要以某种方式发出它的完成信号。在以下示例中,我使用了 Promise:

def randomMark(name:String) = name(0) match 
  case 'R'|'A'|'J'|'S' => Thread.sleep(500); 99
  case  _              => Thread.sleep(500); 80


import scala.concurrent._
import scala.concurrent.duration._
import ExecutionContext.Implicits.global

val returns = Future sequence List( Future(randomMark("Rob")), Future(randomMark("Andy")), Future(randomMark("George")) )
val returns: scala.concurrent.Future[List[Int]] = Future(<not completed>)

val p = Promise[Unit]()

returns onComplete  e =>  val y1 = e.getOrElse("Error"); println(y1); p.success(())  

Await.ready(p.future, 5.seconds)

但是,您可以改用 andThen,如下所示:

def randomMark(name:String) = name(0) match 
  case 'R'|'A'|'J'|'S' => Thread.sleep(500); 99
  case  _              => Thread.sleep(500); 80


import scala.concurrent._
import scala.concurrent.duration._
import ExecutionContext.Implicits.global

val returns = 
  Future sequence List( Future(randomMark("Rob")), Future(randomMark("Andy")), Future(randomMark("George")) ) andThen
   case e =>  val y1 = e.getOrElse("Error"); println(y1)  

Await.ready(returns, 5.seconds)

【讨论】:

感谢维克托的详细解释!在我的示例中,我没有意识到最后两个语句的位置。当我交换他们的位置时,我得到了结果。

以上是关于Scala Future monod 中的 onComplete 方法的主要内容,如果未能解决你的问题,请参考以下文章

Scala之Future超时

Js Deferred/Promise/Future 与 Scala 等函数式语言相比

Scala的Future介绍

发现 scala 类型不匹配 Future[A] 预期 Future[B]

[转] Scala Async 库 (Scala future, await, async)

scala中Future(Int)和FutureInt之间的区别