Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to cancel Future in Scala?

Java Future has cancel method, which can interrupt the thread, which runs the Future task. For example, if I wrap an interruptible blocking call in a Java Future I can interrupt it later.

Scala Future provides no cancel method. Suppose I wrap an interruptible blocking call in a Scala Future. How can I interrupt it?

like image 496
Michael Avatar asked Apr 15 '13 07:04

Michael


People also ask

How does Future work in Scala?

Future represents a result of an asynchronous computation that may or may not be available yet. When we create a new Future, Scala spawns a new thread and executes its code. Once the execution is finished, the result of the computation (value or exception) will be assigned to the Future.

What is Future object in Scala?

A Future is a placeholder object for a value that may not yet exist. Generally, the value of the Future is supplied concurrently and can subsequently be used. Composing concurrent tasks in this way tends to result in faster, asynchronous, non-blocking parallel code.

What is the difference between a Java Future and a Scala Future?

A Java Future works in a synchronous blocking way. It does not work in an asynchronous non-blocking way, whereas a Scala Future works in an asynchronous non-blocking way. If we want an asynchronous non-blocking feature, we should use Java 8's CompletableFuture.

What is a promise and Future Scala?

Promise. The Promise is a writable, single-assignment container that completes a Future. The Promise is similar to the Future. However, the Future is about the read-side of an asynchronous operation, while the Promise is about the write-side.


2 Answers

This is not yet a part of the Futures API, but may be added as an extension in the future.

As a workaround, you could use the firstCompletedOf to wrap 2 futures - the future you want to cancel and a future that comes from a custom Promise. You could then cancel the thus created future by failing the promise:

def cancellable[T](f: Future[T])(customCode: => Unit): (() => Unit, Future[T]) = {   val p = Promise[T]   val first = Future firstCompletedOf Seq(p.future, f)   val cancellation: () => Unit = {     () =>       first onFailure { case e => customCode}       p failure new Exception   }   (cancellation, first) } 

Now you can call this on any future to obtain a "cancellable wrapper". Example use-case:

val f = callReturningAFuture() val (cancel, f1) = cancellable(f) {   cancelTheCallReturningAFuture() }  // somewhere else in code if (condition) cancel() else println(Await.result(f1)) 

EDIT:

For a detailed discussion on cancellation, see Chapter 4 in the Learning concurrent programming in Scala book.

like image 163
axel22 Avatar answered Oct 09 '22 11:10

axel22


I haven't tested this, but this expands on the answer of Pablo Francisco Pérez Hidalgo. Instead of blocking waiting for the java Future, we use an intermediate Promise instead.

import java.util.concurrent.{Callable, FutureTask} import scala.concurrent.{ExecutionContext, Promise} import scala.util.Try  class Cancellable[T](executionContext: ExecutionContext, todo: => T) {   private val promise = Promise[T]()    def future = promise.future    private val jf: FutureTask[T] = new FutureTask[T](     new Callable[T] {       override def call(): T = todo     }   ) {     override def done() = promise.complete(Try(get()))   }    def cancel(): Unit = jf.cancel(true)    executionContext.execute(jf) }  object Cancellable {   def apply[T](todo: => T)(implicit executionContext: ExecutionContext): Cancellable[T] =     new Cancellable[T](executionContext, todo) } 
like image 24
nightingale Avatar answered Oct 09 '22 12:10

nightingale