这是my previous question的后续内容。
假设我有一个任务,它执行可中断的阻止调用。我想使用Future
failure
方法将其作为Promise
和取消运行。
我希望取消按以下方式工作:
如果一个取消任务之前它已完成,我希望任务“立即”完成,如果已经启动阻止呼叫,我将暂停希望Future
调用onFailure
。
如果在任务完成后取消任务,我想获得一个状态,说明由于任务已经完成,取消失败。
有意义吗?是否可以在Scala中实现?有没有这种实现的例子?
答案 0 :(得分:12)
scala.concurrent.Future是只读的,因此一位读者不能为其他读者搞砸。
您似乎应该能够实现您想要的内容,如下所示:
def cancellableFuture[T](fun: Future[T] => T)(implicit ex: ExecutionContext): (Future[T], () => Boolean) = {
val p = Promise[T]()
val f = p.future
p tryCompleteWith Future(fun(f))
(f, () => p.tryFailure(new CancellationException))
}
val (f, cancel) = cancellableFuture( future => {
while(!future.isCompleted) continueCalculation // isCompleted acts as our interrupted-flag
result // when we're done, return some result
})
val wasCancelled = cancel() // cancels the Future (sets its result to be a CancellationException conditionally)
答案 1 :(得分:10)
根据他的评论,这是Victor的代码的可中断版本(Victor,如果我误解,请纠正我)。
object CancellableFuture extends App {
def interruptableFuture[T](fun: () => T)(implicit ex: ExecutionContext): (Future[T], () => Boolean) = {
val p = Promise[T]()
val f = p.future
val aref = new AtomicReference[Thread](null)
p tryCompleteWith Future {
val thread = Thread.currentThread
aref.synchronized { aref.set(thread) }
try fun() finally {
val wasInterrupted = (aref.synchronized { aref getAndSet null }) ne thread
//Deal with interrupted flag of this thread in desired
}
}
(f, () => {
aref.synchronized { Option(aref getAndSet null) foreach { _.interrupt() } }
p.tryFailure(new CancellationException)
})
}
val (f, cancel) = interruptableFuture[Int] { () =>
val latch = new CountDownLatch(1)
latch.await(5, TimeUnit.SECONDS) // Blocks for 5 sec, is interruptable
println("latch timed out")
42 // Completed
}
f.onFailure { case ex => println(ex.getClass) }
f.onSuccess { case i => println(i) }
Thread.sleep(6000) // Set to less than 5000 to cancel
val wasCancelled = cancel()
println("wasCancelled: " + wasCancelled)
}
使用Thread.sleep(6000)
输出为:
latch timed out
42
wasCancelled: false
使用Thread.sleep(1000)
输出为:
wasCancelled: true
class java.util.concurrent.CancellationException
答案 2 :(得分:5)
https://github.com/twitter/util/blob/master/util-core/src/main/scala/com/twitter/util/Future.scala
第563行显示了对此负责的抽象方法。 Scala的期货目前不支持取消。
答案 3 :(得分:2)
您可以使用Monix库而不是Future