等待.ready的替代方案

3

我有以下Scala代码:

val status: Future[String] = Await.ready(Http(address OK as.String), 1 second)

我正在进行一个http调用,并等待一秒钟后得到回答。

有人告诉我使用Await.ready阻塞是不好的实践。

我很好奇可以使用什么来代替。

我可以使用for推导式吗?如何使用?


我猜你的意思是Await.result,因为上面的代码甚至无法编译。 - oxbow_lakes
2个回答

3

阻塞异步操作通常是不好的,否则为什么要将其设计成异步呢?

您可以使用各种Future[T]实现,例如在结果到达时注册继续执行。例如,假设您想将String结果解析为Foo对象。您可以这样做:

val result: Future[Foo] = Http(address OK as.String).map {
  s => parseJson[Foo](s)
}

请注意,当使用 Future[T] 时,除非您同步阻塞,否则您将把它们沿执行调用链上升。
使用 for 推导式也可以实现相同的效果:
for {
 s <- Http(address OK as.String)
} yield (parseJson[Foo](s))

谢谢!我想要等待一段有限的时间(例如,最多1秒钟)。我该怎么做? - bsky
@octavian 这个答案 展示了如何给 Future 添加超时扩展。 - Yuval Itzchakov

2
使用Await.ready不是一个好的实践,因为它会阻塞程序。在大多数情况下,您可以组合和转换futures以达到所需的结果。
但是当绝对必要时,您可以使用阻塞。这是我关于阻塞及其后果的回答:何时使用阻塞,何时不使用阻塞 非阻塞等待
def afterSomeTime(code: => Unit)(duration: FiniteDuration): Unit = {
  someActorSystem.scheduler.scheduleOnce(duration) {
    code
  }
} 

上述函数将在指定时间间隔后调用代码,您可以使用任何其他计时器实现,而不是Akka调度程序。
case class TimeoutException(msg: String) extends Exception(msg)

def timeout[T](future: => Future[T])(duration: FiniteDuration)(implicit ec: ExecutionContext): Future[T] = {

  val promise = Promise[T]()
  future.onComplete(promise tryComplete)

  afterSomeTime {
    promise tryFailure TimeoutException(s"Future timeout after ${duration.toString()}")
  }(duration)

  promise.future
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接