Qualcosa di simile, forse:
object PimpMyFuture {
implicit class PimpedFuture[T](val f: Future[T]) extends AnyVal {
def after(delay: FiniteDuration)(callback: => Unit): Future[T] = {
Future {
blocking { Await.ready(f, delay) }
} recover { case _: TimeoutException => callback }
f
}
}
}
import PimpMyFuture._
Future { Thread.sleep(10000); println ("Done") }
.after(5.seconds) { println("Still going") }
Questa implementazione è semplice, ma raddoppia sostanzialmente il numero di thread necessari - ogni futuro attivo occupa in modo efficace due thread - il che è un po 'dispendioso. In alternativa, è possibile utilizzare le attività pianificate per rendere le vostre attese non bloccanti. Non so di uno scheduler "standard" a Scala (ogni lib ha il proprio), ma per un compito semplice come questo si può usare Java di TimerTask
direttamente:
object PimpMyFutureNonBlocking {
val timer = new java.util.Timer
implicit class PimpedFuture[T](val f: Future[T]) extends AnyVal {
def after(delay: FiniteDuration)(callback: => Unit): Future[T] = {
val task = new java.util.TimerTask {
def run() { if(!f.isCompleted) callback }
}
timer.schedule(task, delay.toMillis)
f.onComplete { _ => task.cancel }
f
}
}
}
Ma 'firstCompletedOf' non annulla l'altra futuro se il primo ritorna. Quindi se la maggior parte del mio futuro dura pochi millisecondi ma voglio aggiungere una dichiarazione di debug per dopo 30s, creerò un sacco di Thread.sleep (30000) che non verrà cancellato, giusto? – pathikrit
@pathikrit sì, ma il risultato sarà gettato via. Se è un futuro non bloccante (ad esempio 'val timeoutFuture = akka.pattern.after (500.milliseconds, using = system.scheduler) {...}' dal post del blog, allora non penso che non sia un problema (non sta bloccando un thread). –