649 Stimmen

Sollte ich immer einen parallelen Stream verwenden, wenn möglich?

Mit Java 8 und Lambdas ist es einfach, über Kollektionen als Streams zu iterieren und genauso einfach, einen parallelen Stream zu nutzen. Zwei Beispiele aus den docs, das zweite mit parallelStream:

myShapesCollection.stream()
    .filter(e -> e.getColor() == Color.RED)
    .forEach(e -> System.out.println(e.getName()));

myShapesCollection.parallelStream() // <-- Dieser nutzt parallel
    .filter(e -> e.getColor() == Color.RED)
    .forEach(e -> System.out.println(e.getName()));

Solange die Reihenfolge nicht wichtig ist, wäre es immer vorteilhaft, den parallel zu verwenden? Man könnte denken, dass es schneller ist, die Arbeit auf mehrere Kerne aufzuteilen.

Gibt es andere Überlegungen? Wann sollte parallel stream verwendet werden und wann sollte der nicht-parallele verwendet werden?

(Diese Frage ist gestellt, um eine Diskussion darüber auszulösen, wie und wann parallele Streams verwendet werden sollen, nicht weil ich denke, dass es immer eine gute Idee ist, sie zu verwenden.)

2voto

Roman Sinyakov Punkte 559

Collection.parallelStream() ist eine großartige Möglichkeit, um parallel zu arbeiten. Allerdings muss man bedenken, dass hierfür effektiv ein gemeinsamer Thread-Pool mit nur wenigen Worker-Threads intern verwendet wird (Standardmäßig entspricht die Anzahl der Threads der Anzahl der CPU-Kerne), siehe ForkJoinPool.commonPool(). Wenn einige Aufgaben des Pools langwierige I/O-gebundene Arbeiten sind, dann können andere, potenziell schnelle parallelStream-Aufrufe stecken bleiben und auf die freien Pool-Threads warten. Dies führt offensichtlich dazu, dass fork-join-Aufgaben nicht-blockierend und kurz sein müssen bzw. mit anderen Worten cpu-gebunden. Zur besseren Verständnis der Details empfehle ich dringend, die java.util.concurrent.ForkJoinTask Javadoc sorgfältig zu lesen, hier sind einige relevante Zitate:

Die Effizienz von ForkJoinTasks hängt davon ab, ... dass sie hauptsächlich als Berechnungsaufgaben dienen, die reine Funktionen berechnen oder auf rein isolierten Objekten arbeiten.

Berechnungen sollten idealerweise synchronisierte Methoden oder Blöcke vermeiden und andere blockierende Synchronisation minimieren

Unterteilbare Aufgaben sollten auch keine blockierende I/O durchführen

Diese Hinweise zeigen den Hauptzweck der parallelStream()-Aufgaben als kurze Berechnungen über isolierten In-Memory-Strukturen. Empfehle außerdem den Artikel Häufige Fallstricke bei der parallelen Stream-Nutzung

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X