Scala之Future超时

Posted junjiang3

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Scala之Future超时相关的知识,希望对你有一定的参考价值。

最近在开发中使用akka http进行请求,返回的是一个future,并且要对future进行超时设置,不知怎么设置,因此学习了下。

一、Future阻塞

首先,scala中的future不支持内置超时,要想达到这样的目的,可以使用Await进行阻塞,具体例子如下:

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

lazy val f = future { Thread.sleep(2000); true }
Await.result(f, 1 second)

上面的代码将超时,报如下错误:

java.util.concurrent.TimeoutException:
    at scala.concurrent.impl.Promise $ DefaultPromise.ready(Promise.scala:219)
    at scala.concurrent.impl.Promise $ DefaultPromise.result(Promise.scala:223)
    at scala.concurrent.Await $$ anonfun $ result $ 1.apply(package.scala:107)
    at scala.concurrent.BlockContext $ DefaultBlockContext $ .blockOn(BlockContext.scala:53) 
...

二、非阻塞Future超时

但是,我们知道,在future上设置阻塞不是官网推荐的一种方式,因为这会浪费一个线程。因此,我们可以使用akka after实现一种非阻塞式的future超时:

import scala.concurrent._
import scala.concurrent.duration._
import ExecutionContext.Implicits.global
import scala.util.{Failure, Success}
import akka.actor.ActorSystem
import akka.pattern.after

val system = ActorSystem("theSystem")

lazy val f = future { Thread.sleep(2000); true }
lazy val t = after(duration = 1 second, using = system.scheduler)(Future.failed(new TimeoutException("Future timed out!")))

val fWithTimeout = Future firstCompletedOf Seq(f, t)

fWithTimeout.onComplete {
case Success(x) => println(x)
case Failure(error) => println(error)
}

但是,注意了,为了确保在执行前,计时还没有开始,必须将after设置lazy val。

但是上述这种模式的缺点是它依赖于akka,因此,我们可以使用纯scala模式,来模仿实现after的功能

为了更容易使用future的超时设置,我们可以使用隐式类来扩展scala future从而支持超时:

import scala.concurrent._
import scala.concurrent.duration.FiniteDuration
import ExecutionContext.Implicits.global
import akka.actor.ActorSystem
import akka.pattern.after

implicit class FutureExtensions[T](f: Future[T]) {
def withTimeout(timeout: => Throwable)(implicit duration: FiniteDuration, system: ActorSystem): Future[T] = {
Future firstCompletedOf Seq(f, after(duration, system.scheduler)(Future.failed(timeout)))
}
}

现在,我们可以随时很方便的给future设置超时了:

import scala.concurrent._
import scala.concurrent.duration._
import scala.util.{ Success, Failure }
import ExecutionContext.Implicits.global
import akka.actor.ActorSystem

implicit val system = ActorSystem("theSystem")
implicit val timeout = 1 second

lazy val f = future { Thread.sleep(2000); true }

f withTimeout new TimeoutException("Future timed out!") onComplete {
case Success(x) => println(x)
case Failure(error) => println(error)
}














































以上是关于Scala之Future超时的主要内容,如果未能解决你的问题,请参考以下文章

Scala之Future

Scala 学习笔记之集合 Try和Future

Scala Future

Scala Future实践踩坑了~

初学scala3——使用future实现并发

Java程序执行超时——Future接口介绍