我想在Scala after(d: FiniteDuration)(callback: => Unit)
中添加一个Future
util,这样我就能做到这一点:
val f = Future(someTask)
f.after(30.seconds) {
println("f has not completed in 30 seconds!")
}
f.after(60.seconds) {
println("f has not completed in 60 seconds!")
}
我该怎么做?
答案 0 :(得分:1)
通常我使用线程池执行器并承诺:
import scala.concurrent.duration._
import java.util.concurrent.{Executors, ScheduledThreadPoolExecutor}
import scala.concurrent.{Future, Promise}
val f: Future[Int] = ???
val executor = new ScheduledThreadPoolExecutor(2, Executors.defaultThreadFactory(), AbortPolicy)
def withDelay[T](operation: ⇒ T)(by: FiniteDuration): Future[T] = {
val promise = Promise[T]()
executor.schedule(new Runnable {
override def run() = {
promise.complete(Try(operation))
}
}, by.length, by.unit)
promise.future
}
Future.firstCompletedOf(Seq(f, withDelay(println("still going"))(30 seconds)))
Future.firstCompletedOf(Seq(f, withDelay(println("still still going"))(60 seconds)))
答案 1 :(得分:0)
一种方法是使用Future.firstCompletedOf
(请参阅此blogpost):
val timeoutFuture = Future { Thread.sleep(500); throw new TimeoutException }
val f = Future.firstCompletedOf(List(f, timeoutFuture))
f.map { case e: TimeoutException => println("f has not completed in 0.5 seconds!") }
其中TimeoutException
是一些例外或类型。
答案 2 :(得分:0)
使用import akka.pattern.after
。如果你想在没有akka的情况下实现它是source code。另一个(java)示例是TimeoutFuture
中的com.google.common.util.concurrent
。
答案 3 :(得分:0)
这样的事情,也许是:
object PimpMyFuture {
implicit class PimpedFuture[T](val f: Future[T]) extends AnyVal {
def after(delay: FiniteDuration)(callback: => Unit): Future[T] = {
Future {
blocking { Await.ready(f, delay) }
} recover { case _: TimeoutException => callback }
f
}
}
}
import PimpMyFuture._
Future { Thread.sleep(10000); println ("Done") }
.after(5.seconds) { println("Still going") }
这个实现很简单,但它基本上使你需要的线程数增加一倍 - 每个活跃的未来有效地占用两个线程 - 这有点浪费。或者,您可以使用计划任务使您的等待无阻塞。我不知道"标准" scala中的scheduler(每个lib都有自己的),但对于像这样的简单任务,你可以直接使用java TimerTask
:
object PimpMyFutureNonBlocking {
val timer = new java.util.Timer
implicit class PimpedFuture[T](val f: Future[T]) extends AnyVal {
def after(delay: FiniteDuration)(callback: => Unit): Future[T] = {
val task = new java.util.TimerTask {
def run() { if(!f.isCompleted) callback }
}
timer.schedule(task, delay.toMillis)
f.onComplete { _ => task.cancel }
f
}
}
}