【问题标题】:Non blocking tail recursive非阻塞尾递归
【发布时间】:2015-10-25 21:38:26
【问题描述】:

我有一个尾递归实现如下

@tailrec
def generate() : String = {
  val token = UUID.randomUUID().toString
  val isTokenExist = Await.result(get(token), 5.seconds).isDefined
  if(isTokenExist) generate()
  else token
}

get(token) 将返回 Future[Option[Token]]

我知道在 Future 中阻塞是不好的。我试图返回 Future[String] 而不是 String。但似乎这是不可能的,除非我等待isTokenExist 完成。

还有其他方法/建议来实现吗?

【问题讨论】:

  • 为什么它必须是尾递归的?为什么 generate 必须返回 String 而不是 Future[String] ?如果你回答了这些问题,你可能会有更好的 API 设计。不是试图推翻你的问题,但这似乎是未来使用和不必要使用尾递归的反模式,IMO。
  • 它实际上是我正在寻找的,不同的实现返回一个Future[String]。但是,我似乎无法找到解决方案。如果你能提供一些启示,我会很高兴:)

标签: scala recursion future


【解决方案1】:

generate 在这种情况下不必是尾递归的,因为它使用 Futures(请阅读:How do I make a function involving futures tail recursive? 进行解释)。

这对你有用吗?

  def generate: Future[String] = {
    val token = UUID.randomUUID().toString
    get(token).flatMap {
      case None => generate
      case _    => Future.successful(token)
    }
  }

【讨论】:

  • 是的,感谢您的帮助。只是想了一下,它不需要尾递归(天哪..我很愚蠢)。感谢帮助:)
  • @Allan 很高兴它对你有用 :) 还值得指出:stackoverflow.com/questions/24308286/…,以防你想重试未来的构造。
【解决方案2】:

get(token) 发生了什么,第一次超过 5s,第二次也不会超过?

如果你真的需要检查(并且冲突非常不太可能),你可能只需要阻止。否则,如果5s不够,方法永远不会返回,很长一段时间后你会得到一个Stackoverflow。

我可能会保持简单:

def generate() : String = {
  val token = UUID.randomUUID().toString
  if(get(token).isDefined) generate()
  else token
}

如果你需要在这段代码中优化一些东西,它可能是get(token)方法。

【讨论】:

  • 嗨,Jean,我正在使用 slick 3 向数据库调用 get(token)。似乎(如果我错了,请纠正我)返回类型必须是Future。您认为屏蔽get(token) 可以吗?
【解决方案3】:

如果你在未来包装get(token),那么你可以使用未来的onComplete 函数。比如:

val f: Future[Token] = Future {
  get(token)
}
f onComplete {
     case Success(token) => generate()
     case Failure(t) => println("An error has occured: " + t.getMessage)
}

欲了解更多信息,请查看:http://docs.scala-lang.org/overviews/core/futures.html

【讨论】:

  • onComplete 返回Unit,你不能用有用的方式递归。
猜你喜欢
  • 2018-03-17
  • 1970-01-01
  • 2019-10-30
  • 2016-07-06
  • 1970-01-01
  • 1970-01-01
  • 2012-11-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多