Scala for-Schleife und Iteratoren
Nehmen wir an ich habe eine sehr große iterierbar Sammlung von Werten (in der Größenordnung von 100.000 String-Einträge Lesen von der Festplatte eins nach dem anderen), und ich mache etwas auf seine kartesischen Produkt (und Schreibe das Ergebnis zurück auf die Festplatte, obwohl ich nicht zeigen, dass hier):
for(v1 <- values; v2 <- values) yield ((v1, v2), 1)
Ich verstehe, dass dies ist nur eine andere Art des Schreibens
values.flatMap(v1 => values.map(v2 => ((v1, v2), 1)))
Diese offenbar bewirkt, dass die gesamte Kollektion für jeden flatMap iteration (oder sogar das gesamte kartesische Produkt?) im Speicher zu behalten. Wenn Sie Lesen, die erste version mit der for-Schleife dies natürlich unnötig. Im Idealfall nur zwei Einträge (die sind zusammen) sollte in Erinnerung bleiben, zu allen Zeiten.
Wenn ich Neuformulierung der ersten version wie folgt:
for(v1 <- values.iterator; v2 <- values.iterator) yield ((v1, v2), 1)
Speicher Verbrauch ist viel geringer, das führt mich zu vermuten, dass diese version muss grundlegend anders. Was genau macht es anders machen, in der zweiten version? Warum Scala nicht implizit verwenden Sie Iteratoren für die erste version? Gibt es eine speedup, wenn Sie nicht mit Iteratoren in einigen Fällen?
Dank! (Und auch Dank der "lmm", antwortete eine frühere version dieser Frage)
- Wenn Sie die Ausbeute eines
((v1, v2), 1)
erstellen Sie eine neue Sammlung, die alle diejenigen Tupel. Also in der Tat das gesamte carthesian Produkt wird in Erinnerung bleiben, nicht? - Nicht unbedingt, Sie geschrieben sind, gleich wieder auf die Festplatte (mit spark/HDFS). Sonst wäre es ja nicht skaliert auch gut 🙂
Du musst angemeldet sein, um einen Kommentar abzugeben.
Die erste version ist streng bewertet, es entsteht eine Reale, konkrete Auflistung mit all diese Werte. Die zweite "nur" über einen
Iterator
können Sie die Iteration über alle Werte; werden Sie erzeugt, wie Sie tatsächlich führen Sie die iteration.Der Hauptgrund Scala standardmäßig das erste ist, weil scala als Sprache erlaubt Nebenwirkungen. Wenn Sie schreiben Ihre zwei mappings als:
dann, was passiert mit der zweiten können Sie überrascht, vor allem in einer größeren Anwendung, wo der iterator könnte erstellt werden ein langer Weg, von wo es tatsächlich gebraucht wird.
Einer Sammlung ausgeführt werden wird, besser als ein iterator, wenn die Karte operation selbst ist teuer, und erstellen Sie es einmal und verwenden es mehrmals - der iterator hat die Neuberechnung der jeweils die Werte, in der Erwägung, dass die Sammlung im Speicher vorhanden. Wohl dieses macht die Kollektion Leistung mehr berechenbar - es verbraucht eine Menge Speicher, aber es ist die gleiche Menge, was die Sammlung ist dann für die.
Wenn Sie möchten, eine Bibliothek, die Sammlungen ist mehr bereit, elide Operationen und optimieren - vielleicht, weil Sie schon schreiben Sie alle Ihre code zu sein, ohne Nebenwirkungen - möchten Sie vielleicht zu prüfen,Paul Philips' neue Anstrengung.
.flatMap
aufIterator
hat eine andere Implementierung, die aufArray
.In Scala
yield
nicht produzieren eine lazy sequence. Mein Verständnis ist, dass man alle Werte auf einmal, so dass Sie indizieren kann Sie alle als eine Sammlung. Zum Beispiel hatte ich Folgendes geschrieben, für einen ray-tracer zu erzeugen Strahlen:welche nicht spektakulär (out of memory), weil es alle Strahlen nach vorne (überraschung!). Mithilfe der
.iterator
Methode, Sie sind insbesondere gefragt für einen faulen iterator. Das obige Beispiel kann modifiziert werden, um diese:welche Werke in einer verzögerten Art und Weise.
yield
nicht automatisch produzieren eine lazy sequence? Es funktioniert, wenn es ist gebaut aus etwas faul (wie Sie hier gezeigt haben).