multithreading - await - Cómo cancelar Future in Scala?
await future scala (4)
Al cancelar, supongo que te gustaría interrumpir violentamente el future
.
Encontrado este segmento de código: https://gist.github.com/viktorklang/5409467
¡Hizo algunas pruebas y parece funcionar bien!
Disfruta :)
Java Future tiene un método de cancel
, que puede interrumpir el hilo, que ejecuta la tarea Future
. Por ejemplo, si cierro una llamada de bloqueo interrumpible en Java Future
, puedo interrumpirla más tarde.
Scala Future no proporciona ningún método de cancel
. Supongamos que envuelvo una llamada de bloqueo interrumpible en un Scala Future
. ¿Cómo puedo interrumpirlo?
Creo que es posible reducir la complejidad de las implementaciones proporcionadas al hacer uso de la interfaz Java 7 Future
y sus implementaciones.
Cancellable
puede construir un futuro Java que será cancelado por su método cancel
. Otro futuro puede esperar hasta que se complete convirtiéndose en la interfaz observable que es inmutable en su estado:
class Cancellable[T](executionContext: ExecutionContext, todo: => T) {
private val jf: FutureTask[T] = new FutureTask[T](
new Callable[T] {
override def call(): T = todo
}
)
executionContext.execute(jf)
implicit val _: ExecutionContext = executionContext
val future: Future[T] = Future {
jf.get
}
def cancel(): Unit = jf.cancel(true)
}
object Cancellable {
def apply[T](todo: => T)(implicit executionContext: ExecutionContext): Cancellable[T] =
new Cancellable[T](executionContext, todo)
}
Esto aún no forma parte de la API de Future
, pero puede agregarse como una extensión en el futuro.
Como solución alternativa, puede usar el firstCompletedOf
para ajustar 2 futuros: el futuro que desea cancelar y un futuro que proviene de una Promise
personalizada. A continuación, puede cancelar el futuro así creado fallando la promesa:
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)
}
Ahora puede llamar esto en cualquier futuro para obtener un "contenedor cancelable". Ejemplo de uso-caso:
val f = callReturningAFuture()
val (cancel, f1) = cancellable(f) {
cancelTheCallReturningAFuture()
}
// somewhere else in code
if (condition) cancel() else println(Await.result(f1))
EDITAR:
Para una discusión detallada sobre la cancelación, vea el Capítulo 4 en la programación concurrente de Aprendizaje en el libro de Scala .
No lo he probado, pero esto se amplía a la respuesta de Pablo Francisco Pérez Hidalgo. En lugar de bloquear la espera del Future
java, utilizamos una Promise
intermedia en su lugar.
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)
}