coś takiego, być może:
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") }
Ta implementacja jest prosta, ale to w zasadzie podwaja liczbę wątków trzeba - każda aktywna przyszłość skutecznie zajmuje dwa wątki - co jest nieco marnotrawstwem. Alternatywnie możesz użyć zaplanowanych zadań, aby twoje oczekiwania nie były blokowane. Nie wiem, od „standardowego” scheduler w Scala (lib każdy ma własne), ale dla prostego zadania jak to można użyć Java TimerTask
bezpośrednio:
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
}
}
}
Ale 'firstCompletedOf' nie anulować drugi przyszłość, jeśli pierwszy powróci. Więc jeśli większość moich przyszłości trwa kilka milisekund, ale chcę dodać instrukcję debugowania po 30 sekundach, będę tworzył wiele Thread.sleep (30000), które nie zostaną anulowane, prawda? – pathikrit
@pathikrit tak, ale wynik zostanie odrzucony. Jeśli jest to nieblokująca przyszłość (np. 'Val timeoutFuture = akka.pattern.after (500.milliseconds, using = system.scheduler) {...}' z posta na blogu, to nie sądzę, że to nie problem (nie blokuje wątku). –