我正在尝试在Scala中实现预定的未来。我希望它等待特定时间然后执行正文。到目前为止,我尝试了以下简单的方法
val d = 5.seconds.fromNow
val f = future {Await.ready(Promise().future, d.timeLeft); 1}
val res = Await.result(f, Duration.Inf)
但我正在接受未来的TimeoutExcpetion。这甚至是正确的方法还是我应该只使用Java中的ScheduledExecutor?
答案 0 :(得分:61)
Akka有akka.pattern:
def after[T](duration: FiniteDuration, using: Scheduler)(value: ⇒ Future[T])(implicit ec: ExecutionContext): Future[T]
“返回一个scala.concurrent.Future,它将在指定的持续时间后以提供的值成功或失败完成。”
答案 1 :(得分: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 ) )
}
}
可以这样使用:
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits._
DelayedFuture( 5 seconds )( println("Hello") )
请注意,与java预定期货不同,此实现不会让您取消未来。
答案 2 :(得分:16)
如果您希望在没有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
}
答案 3 :(得分: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
}
答案 4 :(得分: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))
}
但我不推荐它。在这样做时,你会在未来阻塞(阻止等待永远不会完成的Promise
),我认为阻止ExecutionContext
被阻止。我会按照你的说法调查使用java预定执行程序,或者你可以考虑使用Akka作为@ alex23推荐。
答案 5 :(得分:2)
所有其他解决方案使用akka或每个延迟任务阻止一个线程。更好的解决方案(除非您已经在使用akka)是使用java的ScheduledThreadPoolExecutor。这是一个scala包装器的例子:
答案 6 :(得分:-4)
最短的解决方案,可能是使用scala-async:
import scala.async.Async.{async, await}
def delay[T](value: T, t: duration): Future[T] = async {
Thread.sleep(t.toMillis)
value
}
或者如果你想延迟执行一个块
def delay[T](t: duration)(block: => T): Future[T] async {
Thread.sleep(t.toMillis)
block()
}