我对Scala很陌生,有Java的背景。
我面临的问题是我想在 5 分钟后执行一个函数。并且可以随时取消此操作。
在java中,我基本上会使用TimerTask,并将其设置为5分钟。如果我想取消,我只需调用cancel
方法。好消息是,我可以在Scala中使用Java类。但是当我还在学习Scala时,我只是想知道我是否错过了以更好的方式实现这一目标的更好方法。我遇到了Future
和Await.result
Scala 课程,但我很难弄清楚。
有什么建议吗?
scala 库中的Future
不可取消。你要做的是实现某种条件,并确保你的"东西"只在条件为真的情况下运行。
您可能想查看monix.Task
,这是可取消的:https://monix.io/docs/2x/eval/task.html
从他们的文档中:
import monix.eval.Task
import monix.execution.CancelableFuture
import concurrent.duration._
val task = Task(1 + 1).delayExecution(1.second)
val result: CancelableFuture[Int] =
task.runAsync
// If we change our mind
result.cancel()
通常,如果您使用某种框架,它将提供自己的抽象来处理计划任务。Finagle有一个Timer
类,例如基于Netty的HashedWheelTimer
,Akka有Scheduler
,等等。 (最好在整个应用程序中使用相同的调度框架,因为这可以更有效地使用资源(。
如果你只是在没有任何框架的情况下编写"vanilla"scala代码,那么直接使用TimerTask
并没有错,或者,也许,在它周围做一个小包装器,这样在scala代码中使用它就不会那么尴尬:
class FutureTask[T](f: => Future[T]) extends TimerTask {
val promise = Promise[T]()
def run(): Unit = promise.completeWith(f)
override def cancel() = {
val result = super.cancel
if(result) promise.complete(Failure(new CancellationException))
result
}
}
object FutureTask {
implicit def toFuture[T](task: FutureTask[T]) = task.promise.future
def scheduleFlat[T](when: Duration)(f: => Future[T])(implicit timer: Timer = defaultTimer): FutureTask[T] = {
val task = new FutureTask(f)
timer.schedule(task, when.toMillis)
task
}
def schedule[T](when: Duration)(f: => T)(implicit timer: Timer = defaultTimer, ctx: ExecutionContext): FutureTask[T] =
scheduleFlat(when)(Future(f))(timer)
val defaultTimer = new java.util.Timer(true)
}
现在,您可以执行以下操作:
val someTask = FutureTask
.schedule(5 seconds) { println("Hello!") }
someTask.onComplete { result => println("Completed with " + result) }
someTask.cancel
Await.result(someTask, 2 seconds)
等。