提问人:Michael 提问时间:4/10/2021 更新时间:4/11/2021 访问量:202
如何在 Scala 中为未来添加截止日期?
How to add a deadline to a future in Scala?
问:
假设我有一个函数,并希望它返回一个在截止日期之前完成的新未来。所以我正在编写一个这样的新函数fab: A => Future[B]
deadlined
def deadlined[B](fut: => Future[B], deadline: Deadline): Future[B] = ???
现在我正在使用,但可以按照建议使用。不过,最好的解决方案可能是将调度实现抽象出来,并按照注释中的建议在测试中模拟它。java.util.Timer
ScheduledThreadPoolExecutor
object Deadlined {
private val timer = new java.util.Timer() // todo: replace it with a wrapper
def apply[B](fut: => Future[B], deadline: Deadline)(implicit ec: ExecutionContext): Future[B] = {
val promise = Promise[B]()
val timerTask = new java.util.TimerTask {
override def run(): Unit = promise.failure(new Exception(s"$deadline is exceeded"))
}
timer.schedule(timerTask, deadline.timeLeft.toMillis)
fut.transform { result =>
timerTask.cancel()
result match {
case Success(b) => promise.success(b)
case Failure(t) => promise.failure(t)
}
result
}
promise.future
}
}
这有意义吗?我还想知道如何从对我上一个问题的回答中剔除一个共同的部分和延迟。Deadlined
答:
2赞
Viktor Klang
4/11/2021
#1
我可能会做类似下面的事情,这样我就可以为任何 Future(YMMV、Caveat Emptor 等)添加一个截止日期:
import scala.concurrent.{Future, ExecutionContext}
import scala.concurrent.duration.FiniteDuration
import java.util.{Timer, TimerTask}
implicit class DeadlineFuture[T](future: Future[T]) {
def deadline(d: FiniteDuration)(implicit timer: Timer): Future[T] = {
if (future.isCompleted) future
else {
val promise = Promise[T]()
val timerTask = new TimerTask {
override def run(): Unit = promise.tryFailure(new Exception(s"$d is exceeded"))
}
timer.schedule(timerTask, d.toMillis)
future.onComplete(_ => timerTask.cancel())(ExecutionContext.parasitic)
promise.completeWith(future).future
}
}
}
// Usage:
Future.never.deadline(5.seconds).onComplete(println)
评论
0赞
Michael
4/11/2021
谢谢。为什么不是承诺?tryFailure
failure
1赞
Viktor Klang
4/11/2021
因为如果承诺在未来完成,那么在 tmer 任务中将抛出执行。(取消 TimerTask 和 TimerTask 尝试设置失败之间存在竞争。promise.failure(…)
0赞
Michael
4/11/2021
哦,我明白。谢谢。
0赞
Michael
4/11/2021
这是正确的,即优化并且该函数在没有它的情况下工作吗?if (future.isCompleted) future
0赞
Viktor Klang
4/12/2021
事实上,Michael,在某些情况下,你会希望减少在已知不需要 TimerTasks 时调度它们的压力。
评论
Deadline
Future.firstCompletedOf