• 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)
    }
  • 相关阅读:
    201621123037 《Java程序设计》第9周学习总结
    201621123037 《Java程序设计》第8周学习总结
    201621123037 《Java程序设计》第7周学习总结
    201621123037 《Java程序设计》第6周学习总结
    201621123037 《Java学习设计》 第五周学习总结
    201621123037 《Java程序设计》第4周学习总结
    201621123037 《Java程序设计》第3周学习总结
    myeclipse报Unhandld event loop Exception怎么解决
    Ajax 完整教程
    在JSP程序中我用新图片替换掉了原图片(名字,格式相同),为什么打开网页显示的还是以前的图片呢
  • 原文地址:https://www.cnblogs.com/junjiang3/p/9695426.html
Copyright © 2020-2023  润新知