Scala - ScheduledFuture

Bob*_*r02 31 scala future

我正在尝试在Scala中实现预定的未来.我希望它等待特定时间然后执行正文.到目前为止,我尝试了以下简单方法

val d = 5.seconds.fromNow

val f = future {Await.ready(Promise().future, d.timeLeft); 1}

val res = Await.result(f, Duration.Inf)
Run Code Online (Sandbox Code Playgroud)

但我正在接受未来的TimeoutExcpetion.这甚至是正确的方法还是我应该只使用Java中的ScheduledExecutor?

Vik*_*ang 63

Akka有akka.pattern:

def after[T](duration: FiniteDuration, using: Scheduler)(value: ? Future[T])(implicit ec: ExecutionContext): Future[T]
Run Code Online (Sandbox Code Playgroud)

"返回一个scala.concurrent.Future,它将在指定的持续时间之后通过提供的值的成功或失败来完成."

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

  • 这可以在没有演员系统的情况下使用吗? (11认同)
  • 这个答案应该标记为最佳答案! (3认同)
  • 真的不用说为什么这对并发性很好,这是没用的 (2认同)

Rég*_*les 18

单独使用标准库,没有任何东西可以开箱即用.对于大多数简单的用例,您可以使用如下的小助手:

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 ) )
  }
}
Run Code Online (Sandbox Code Playgroud)

这可以这样使用:

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

DelayedFuture( 5 seconds )( println("Hello") )
Run Code Online (Sandbox Code Playgroud)

请注意,与java预定期货不同,此实现不会让您取消将来.

  • 我注意到`private val timer = new Timer`使用默认值不作为deamon线程运行,因此可能会停止使用此代码关闭处理偶尔执行的任务?也许最好使用`private val timer = new Timer(true)`来防止进程挂起? (2认同)

Arn*_*sen 17

如果您想在没有Akka的情况下安排完成,您可以使用常规Java Timer来安排完成的承诺:

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
}
Run Code Online (Sandbox Code Playgroud)


aga*_*bor 7

我的解决方案与Régis非常相似,但我使用Akka安排:

 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
  }
Run Code Online (Sandbox Code Playgroud)


cmb*_*ter 6

您可以将代码更改为以下内容:

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))
}
Run Code Online (Sandbox Code Playgroud)

但我不推荐它.在这样做的时候,你会在一个Future中阻塞(阻塞以等待Promise永远不会完成的事情),并且我认为阻止它ExecutionContext是非常气馁的.我会按照你的说法调查使用java预定执行程序,或者你可以考虑使用Akka作为@ alex23推荐.

  • `Await.ready`使用`blocking`,所以如果你在五秒钟内完成工作,至少底层池可以为它启动一个线程. (5认同)
  • 这个(或原始问题)所需的导入工作将很高兴.我认为它们是scala.concurrent.duration._和scala.concurrent._ (2认同)