【问题标题】:Scala Future not entering onComplete()Scala Future 未进入 onComplete()
【发布时间】:2017-08-01 06:01:03
【问题描述】:

我试图从导致Future 的代码的sn-p 中获取值,但是当我运行代码时,结果发现它从未进入onComplete 函数。是不是我做错了什么?

我也尝试过使用地图,因为它在其他帖子中被建议过,但没有成功

override def findOrCreate(phoneNumber: String, creationReason: String): Future[AvroCustomer] = {

      //query for customer in db
      val avroCustomer: Future[AvroCustomer] = customerByPhone(phoneNumber)

      avroCustomer.onComplete({
        case Success(null) => {
          createUserAndEvent(phoneNumber, creationReason, 1.0)
        }

        case Success(customer) => {
            Future.successful(customer)
        }

        case Failure(exception) => {

        }
})

【问题讨论】:

  • 您是否正在等待Future 在调用它的代码中完成运行?您是否可能收到Failure 并忽略它?
  • 也许你的 Future 实际上在很长一段时间内都没有完成。您不妨试试Await.result 进行调试。
  • 期货最终在那里 -> 正如@jkinkead 指出的那样,您必须在某个时候等待它们。如果您在程序结束时运行Future 并且不等待它,您将永远看不到结果。
  • 我认为您提供的代码无法编译

标签: scala functional-programming future


【解决方案1】:

回答以扩展评论。这个虚拟程序不会打印任何东西。

import scala.concurrent.Future
import scala.util.{Failure, Success}
import scala.concurrent.ExecutionContext.Implicits.global

object Quickie {
  def main(args: Array[String]): Unit = {
    val addOneInFuture: Future[Int] = Future(addOne(3))

    addOneInFuture.onComplete {
      case Success(s) => println(s)
      case Failure(ex) => println(ex.toString)
      case _ => println("what the hell happened")
    }

  }

  def addOne(x: Int): Int = x + 1
}

我启动了一个新线程,但由于永远不需要该值,我将看不到打印的 4。但是,添加一个简单的 AwaitThreed.sleep(_eternity_),甚至是另一个 println,你就会看到结果。关于 Scala 中的 Futures 要了解的一件事是,您希望将它们组合起来并将它们视为集合(因此有 for-comprehensions 用于它们)并且您很少想做某事并打印。如果你做一些 db 或 rest IO,你无论如何都要进一步处理数据。

您可以阅读 Daniel Westheide 的一个古老但黄金的博客系列。 http://danielwestheide.com/blog/2013/01/09/the-neophytes-guide-to-scala-part-8-welcome-to-the-future.html

【讨论】:

  • 我赞成认为这是正确的,但我实际上并不认为它是正确的。您的程序不打印任何内容的原因仅仅是因为它在有时间这样做之前就退出了。它与“需要”的值无关。新手指南也没有提到这一点
【解决方案2】:

Imo,不要使用 OnComplete,它不会返回您想要的(OnComplete 是 Unit 类型的方法),首先,您可以尝试在 DB 端捕获异常,使用 Try 类型或恢复,然后让你的方法返回一个Option[AvroCustomer]

这是 scala 可选包装器类型的完美用例(使用空类型的 Scala-tastic 方式)。如果 customerByPhone 出于某种原因返回 null,您可以在 db 函数端捕获它并将其转换为可选类型。

即非常快,如果它是可空类型:

def customerByPhone(s: String) = {
  ... //Some code
  db.run(query).map(Option(_))
}

这会产生一个Option[avroCustomer],然后您可以这样链接:

override def findOrCreate(phoneNumber: String, creationReason: String): Future[AvroCustomer] = {

      //query for customer in db
      customerByPhone(phoneNumber).flatMap {
         case Some(customer) => Future.successful(customer)

         case None => createUserAndEvent(phoneNumber, creationReason, 1.0) //I'm assuming this returns a futures.
      }
}     

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-05-30
    • 2017-04-20
    • 1970-01-01
    • 1970-01-01
    • 2014-05-22
    • 2019-09-16
    • 1970-01-01
    • 2018-04-17
    相关资源
    最近更新 更多