2012-10-12 11 views
5

The easiest way to convert a Java Collection to a Scala equivalent is using JavaConversions, since Scala 2.8.. Diese impliziten Defs geben Wrapper für die enthaltene Java Collection zurück.So erstellen Sie eine parallele Scala-Sammlung aus einer Java-Sammlung

Scala 2.9 führte parallele Sammlungen ein, bei denen Operationen an einer Sammlung parallel ausgeführt und das Ergebnis später gesammelt werden kann. Dies ist einfach zu implementieren, eine bestehende Sammlung in einen parallelen einer Umwandlung ist so einfach wie:

myCollection.par 

Aber es gibt ein Problem bei der Verwendung ‚par‘ auf von Java Sammlungen umgewandelt Sammlungen mit JavaConversions. Wie in Parallel Collection Conversions beschrieben, inhärent sequentielle Sammlungen werden in eine neue parallele Sammlung ‚gezwungen‘, indem alle Werte und Addieren derselben zu dem neuen parallel Sammlung Auswertung:

Andere Sammlungen, wie Listen, Warteschlangen oder Ströme sind inhärent sequentiell in dem Sinne, dass die Elemente zugegriffen werden muss eine nach die andere. Diese Sammlungen werden in ihre parallelen Varianten konvertiert, indem die Elemente in eine ähnliche parallele Sammlung kopiert werden. Für Beispiel wird eine Funktionsliste in eine standardmäßige unveränderliche parallele Sequenz konvertiert, die ein Parallelvektor ist.

Dies führt zu Problemen, wenn die ursprüngliche Java-Sammlung faul ausgewertet werden soll. Wenn zum Beispiel nur ein Java-Iterable zurückgegeben wird, das später in ein Scala-Iterable konvertiert wird, gibt es keine Garantie, dass der Inhalt des Iterable beabsichtigt ist, eifrig zugegriffen zu werden oder nicht. Wie also sollte eine parallele Sammlung aus einer Java-Sammlung erstellt werden, ohne die Kosten für die Bewertung jedes Elements zu tragen? Es sind diese Kosten, die ich zu vermeiden versuche, indem ich eine parallele Sammlung verwende, um sie parallel auszuführen und hoffentlich die ersten n Ergebnisse, die angeboten werden, zu "nehmen".

Laut Parallel Collection Conversions gibt es eine Reihe von Auflistungstypen, die konstante Zeit kosten, aber es scheint keine Möglichkeit zu geben, eine Garantie zu erhalten, dass diese Typen von JavaConversions erstellt werden können (z. B. 'Set' kann erstellt werden). aber ist das ein 'HashSet'?).

+1

Beachten Sie, dass es eine bessere Idee wäre, JavaConverter als JavaConversions als letztere zu verwenden, mit der Möglichkeit, etwas wie .asScala.toList.par zu tun. –

Antwort

4

Erstens ist jede Sammlung, die über JavaConversion aus einer Java-Sammlung erhalten wird, keine standardmäßig parallelisierbare Scala-Sammlung - dies bedeutet, dass sie immer in ihre entsprechende parallele Sammlungsimplementierung erneut ausgewertet wird. Der Grund dafür ist, dass die parallele Ausführung zumindest auf den Konzepten von Splitters beruht - sie muss in kleinere Teilmengen aufgeteilt werden können, an denen dann verschiedene Prozessoren arbeiten können.

Ich weiß nicht, wie Ihre Java-Sammlung im Sinne der Datenstruktur aussieht, aber wenn es sich um ein baumähnliches Ding oder ein Array darunter handelt, deren Elemente träge ausgewertet werden, können Sie problemlos Splitter implementieren.

Wenn Sie nicht möchten, eifrig force eine faule Sammlung, die eine Java-Sammlung API implementiert, dann ist Ihre einzige Option implement a new type of a parallel collection für diese bestimmte faule Java-Sammlung. In dieser neuen Implementierung müssen Sie Mittel bereitstellen, um den Iterator aufzuteilen (d. H. Splitter).

Sobald Sie diese neue parallele Sammlung implementiert haben, die weiß, wie Sie Ihre Datenstruktur teilen, sollten Sie einen eigenen Scala-Wrapper für Ihre spezifische Java-Sammlung erstellen (an dieser Stelle ist es nur ein kleines Extra), sehen Sie, wie es gemacht wird in JavaConversions) und überschreiben Sie par, um Ihre spezifische parallele Sammlung zurückzugeben.

Sie könnten dies auch generisch für indizierte Sequenzen tun. Da Ihre Java-Sammlung eine Sequenz (in Java List) mit einer besonders effizienten get-Methode ist, könnten Sie Splitter als Iterator implementieren, der get innerhalb des anfänglichen Bereichs von bis size - 1 aufruft und durch Unterteilung dieses Bereichs aufgeteilt wird.

Wenn Sie dies tun, sind Patches für die Standardbibliothek immer willkommen.

1

Parallel erfordert wahlfreien Zugriff und java.lang.Iterable bietet es nicht. Dies ist eine fundamentale Diskrepanz, bei der keine Menge an Conversions Sie überhäufen kann.

Um eine nicht-programmatische Analogie zu verwenden, können Sie keine Person von Australien nach England bringen, indem Sie gleichzeitig eine Person aus Singapur nach England und eine andere aus Australien nach Singapur schicken.

Oder in der Programmierung, wenn Sie einen Livestream von Daten verarbeiten, können Sie es nicht parallelisieren, indem Sie die Daten ab sofort zur gleichen Zeit wie die Daten von vor fünf Minuten verarbeiten, ohne Latenz hinzuzufügen.

Sie benötigen etwas, das mindestens einen wahlfreien Zugriff bietet, wie java.util.List.listIterator (Int) anstelle von Iterable.

+0

Ich nehme an, ich nahm an, dass jeder Aufruf das nächste Element (d. H. Iterable.iterator(). Next()) in einem Thread ausgeführt wurde. –

Verwandte Themen