Wie mache ich eine Funktion mit futures tail-rekursiv?
In meiner Scala app, ich habe eine Funktion aufruft, die eine Funktion liefert ein Ergebnis vom Typ Future[T]. Ich übergeben zu müssen, das zugeordnete Ergebnis in meinem rekursiven Aufruf der Funktion. Ich will, dass das tail-rekursiv ist, aber die Karte (oder flatMap) bricht die Fähigkeit, das zu tun. Ich bekomme die Fehlermeldung "der Rekursive Aufruf nicht in den Schwanz-position."
Unten ist ein einfaches Beispiel für dieses Szenario. Wie können diese modifiziert werden, so dass der Aufruf tail-rekursiv (ohne das untergraben der Vorteile von Futures mit einer Erwarten.Ergebnis())?
import scala.annotation.tailrec
import scala.concurrent.{Await, Future}
import scala.concurrent.duration._
implicit val ec = scala.concurrent.ExecutionContext.global
object FactorialCalc {
def factorial(n: Int): Future[Int] = {
@tailrec
def factorialAcc(acc: Int, n: Int): Future[Int] = {
if (n <= 1) {
Future.successful(acc)
} else {
val fNum = getFutureNumber(n)
fNum.flatMap(num => factorialAcc(num * acc, num - 1))
}
}
factorialAcc(1, n)
}
protected def getFutureNumber(n: Int) : Future[Int] = Future.successful(n)
}
Await.result(FactorialCalc.factorial(4), 5.seconds)
InformationsquelleAutor Donuts | 2013-06-06
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich könnte mich irren, aber Ihre Funktion nicht tail recursive in diesem Fall.
Tail recursion hilft uns nicht verbrauchen, die Stapel im Fall verwenden wir rekursive Funktionen. In Ihrem Fall, sind wir jedoch nicht tatsächlich verbrauchen die Stapel in der Art eines typischen rekursiven Funktion.
Dies ist, weil die "rekursiven" Aufruf asynchron erfolgen, auf einige Faden von der Ausführungskontext. So ist es sehr wahrscheinlich, dass dieser rekursive Aufruf nicht auch sich auf dem gleichen Stapel wie die erste Aufforderung.
Den
factorialAcc
Methode erstellt das künftige Objekt, die schließlich Auslöser der "rekursiven" Aufruf asynchron. Danach ist es sofort tauchte aus dem Stapel.So, das ist eigentlich nicht stack Rekursion und der stack wächst nicht proportional zu n ist, bleibt es in etwa auf eine Konstante Größe.
Können Sie ganz einfach prüfen, indem Sie eine Ausnahme auslösen, die irgendwann in der
factorialAcc
Methode und Prüfung der stack-trace.Schrieb ich Ihr Programm zu erhalten, eine besser lesbare stack-trace:
Und die Ausgabe ist:
Damit Sie sehen können, dass der stack ist eigentlich kurz. Wenn dieser stack Rekursion sollte man gesehen haben über 97 Aufrufe der
factorialAcc
Methode. Stattdessen sehen Sie nur einen.Ich bin der Untersuchung etwas ähnliches wie here mit Spielen die WS-client-Bibliothek. Sie haben mehr Einblick in das memory-leak-Problem?
Wie würde die Stapel bleiben in etwa auf eine Konstante Größe? würde die Gesamtgröße schluckte als Stapel nicht nur eine Verteilung über verschiedene threads?
twitter.com/viktorklang/status/433957085621940225
InformationsquelleAutor Marius Danila
Wie über die Verwendung von foldLeft statt?
InformationsquelleAutor warpedjavaguy
Hier ein foldLeft Lösung, ruft eine andere Funktion zurückgibt, die eine Zukunft haben.
InformationsquelleAutor warpedjavaguy
Machen
factorialAcc
Int zurückgeben und nur wickeln Sie es in eine Zukunft, in derfactorial
Funktion.dürfte.
InformationsquelleAutor Cubic