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
val d = 5.seconds.fromNow
val f = future {Await.ready(Promise().future, d.timeLeft); 1}
val res = Await.result(f, Duration.Inf)
but I am getting the TimeoutExcpetion on the future. Is this even the correct approach or should I simply use the ScheduledExecutor from Java?
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.
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."
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.
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
}
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
}
All the other solutions use either akka or block a thread per delayed task. A better solution (unless you are already using akka) is to use java's ScheduledThreadPoolExecutor. Here's an example of a scala wrapper for that:
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()
}
来源:https://stackoverflow.com/questions/16359849/scala-scheduledfuture