Scala - ScheduledFuture

前端 未结 7 1103
感动是毒
感动是毒 2020-12-08 04:27

I am trying to implement scheduled future in Scala. I would like it to wait specific time and then execute the body. So far I tried the following, simple approach

         


        
相关标签:
7条回答
  • 2020-12-08 04:57

    If you want schedule the completion without Akka, you can use a regular Java Timer to schedule a promise to complete:

    def delay[T](delay: Long)(block: => T): Future[T] = {
      val promise = Promise[T]()
      val t = new Timer()
      t.schedule(new TimerTask {
        override def run(): Unit = {
          promise.complete(Try(block))
        }
      }, delay)
      promise.future
    }
    
    0 讨论(0)
  • 2020-12-08 05:02

    You could change your code to something like this:

    val d = 5.seconds.fromNow
    val f = Future {delay(d); 1}
    val res = Await.result(f, Duration.Inf)
    
    def delay(dur:Deadline) = {
      Try(Await.ready(Promise().future, dur.timeLeft))
    }
    

    But I would not recommend it. In doing so, you would be blocking in a Future (blocking to wait for that Promise that will never complete), and I think blocking in the ExecutionContext is greatly discouraged. I would either look into using the java scheduled executor as you stated or you could look into using Akka as @alex23 recommended.

    0 讨论(0)
  • 2020-12-08 05:03

    My solution is pretty similar to Régis's but I use Akka to schedule:

     def delayedFuture[T](delay: FiniteDuration)(block: => T)(implicit executor : ExecutionContext): Future[T] = {
        val promise = Promise[T]
    
        Akka.system.scheduler.scheduleOnce(delay) {
          try {
            val result = block
            promise.complete(Success(result))
          } catch {
            case t: Throwable => promise.failure(t)
          }
        }
        promise.future
      }
    
    0 讨论(0)
  • 2020-12-08 05:03

    Shortest solution for this, is probably making use of scala-async:

    import scala.async.Async.{async, await}
    
    def delay[T](value: T, t: duration): Future[T] = async {
      Thread.sleep(t.toMillis)
      value
    }
    

    Or in case you want delayed execution of a block

    def delay[T](t: duration)(block: => T): Future[T] async {
      Thread.sleep(t.toMillis)
      block()
    }
    
    0 讨论(0)
  • 2020-12-08 05:11

    Akka has akka.pattern:

    def after[T](duration: FiniteDuration, using: Scheduler)(value: ⇒ Future[T])(implicit ec: ExecutionContext): Future[T]
    

    "Returns a scala.concurrent.Future that will be completed with the success or failure of the provided value after the specified duration."

    http://doc.akka.io/api/akka/2.2.1/#akka.pattern.package

    0 讨论(0)
  • 2020-12-08 05:13

    There is nothing to do that out of the box using the standard library alone. For most simple use cases, you can use a little helper such as this:

    object DelayedFuture {
      import java.util.{Timer, TimerTask}
      import java.util.Date
      import scala.concurrent._
      import scala.concurrent.duration.FiniteDuration
      import scala.util.Try
    
      private val timer = new Timer(true)
    
      private def makeTask[T]( body: => T )( schedule: TimerTask => Unit )(implicit ctx: ExecutionContext): Future[T] = {
        val prom = Promise[T]()
        schedule(
          new TimerTask{
            def run() {
              // IMPORTANT: The timer task just starts the execution on the passed
              // ExecutionContext and is thus almost instantaneous (making it 
              // practical to use a single  Timer - hence a single background thread).
              ctx.execute( 
                new Runnable {
                  def run() {
                    prom.complete(Try(body))
                  }
                }
              )
            }
          }
        )
        prom.future
      }
      def apply[T]( delay: Long )( body: => T )(implicit ctx: ExecutionContext): Future[T] = {
        makeTask( body )( timer.schedule( _, delay ) )
      }
      def apply[T]( date: Date )( body: => T )(implicit ctx: ExecutionContext): Future[T] = {
        makeTask( body )( timer.schedule( _, date ) )
      }
      def apply[T]( delay: FiniteDuration )( body: => T )(implicit ctx: ExecutionContext): Future[T] = {
        makeTask( body )( timer.schedule( _, delay.toMillis ) )
      }
    }
    

    This can be used like this:

    import scala.concurrent.duration._
    import scala.concurrent.ExecutionContext.Implicits._
    
    DelayedFuture( 5 seconds )( println("Hello") )
    

    Note that unlike java scheduled futures, this implementation will not let you cancel the future.

    0 讨论(0)
提交回复
热议问题