事情是这样的,也许:
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中的一个“标准”调度(每个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
}
}
}
但是'firstCompletedOf'不会取消其他未来如果第一个返回。所以如果我的期货的大部分时间是最后几毫秒,但我想在30秒后添加一条调试语句,我将创建大量的Thread.sleep(30000),它不会被正确取消? – pathikrit
@pathikrit是的,但结果将被扔掉。如果这是一个无阻塞的未来(例如,博客文章中的'val timeoutFuture = akka.pattern.after(500.milliseconds,using = system.scheduler){...}',那么我认为这不是问题(它不会阻塞线程)。 –