parallel flatMap immer sequentiell

8

Angenommen, ich habe diesen Code:

%Vor%

Ausgabe ist derselbe Thread-Name, also gibt es keinen Vorteil von parallel hier - was ich damit meine ist, dass es einen einzelnen Thread gibt, der all die Arbeit erledigt.

Innerhalb flatMap gibt es diesen Code:

%Vor%

Ich verstehe, die sequential -Eigenschaft zu erzwingen, wenn der "äußere" Stream parallel wäre (sie könnten wahrscheinlich blockieren), "äußere" müsste warten, bis "flatMap" fertig ist und umgekehrt (seit dem gleichen Common) Pool wird verwendet) Aber warum immer das erzwingen?

Ist das eines der Dinge, die in einer späteren Version ändern könnten?

    
Eugene 11.07.2017, 14:58
quelle

1 Antwort

8

Es gibt zwei verschiedene Aspekte.

Erstens gibt es nur eine einzige Pipeline, die entweder sequenziell oder parallel ist. Die Wahl von sequentiell oder parallel am inneren Strom ist irrelevant. Beachten Sie, dass der downstream Consumer, den Sie im zitierten Code-Snippet sehen, die gesamte nachfolgende Stream-Pipeline darstellt. In Ihrem Code, der mit .collect(Collectors.toSet()); endet, fügt dieser Consumer schließlich die einzelnen Elemente zu einer einzelnen Set -Instanz hinzu fadensicher. Die Verarbeitung des inneren Stroms parallel zu diesem einzelnen Verbraucher würde den gesamten Vorgang unterbrechen.

Wenn ein äußerer Stream aufgeteilt wird, kann dieser zitierte Code möglicherweise gleichzeitig mit verschiedenen Konsumenten aufgerufen werden, die zu anderen Sets hinzugefügt werden. Jeder dieser Aufrufe würde ein anderes Element der äußeren Stream-Zuordnung zu einer anderen inneren Stream-Instanz verarbeiten. Da Ihr äußerer Stream nur aus einem einzelnen Element besteht, kann er nicht geteilt werden.

Der Weg, dies wurde implementiert, ist auch der Grund für die Warum filter () nach flatMap () ist "nicht vollständig" faul in Java-Streams? Problem, da forEach im inneren Stream aufgerufen wird, der alle Elemente an den Downstream-Consumer weitergibt. Wie von dieser Antwort demonstriert, ist eine alternative Implementierung möglich, die Faulheit und Teilstromaufteilung unterstützt. Aber das ist eine grundlegend andere Art, es zu implementieren. Das aktuelle Design der Stream-Implementierung funktioniert meist nach der Konsumentenzusammensetzung, so dass am Ende der Quell-Spliterator (und die davon abgespaltenen) ein Consumer erhält, das die gesamte Stream-Pipeline entweder in tryAdvance oder forEachRemaining darstellt. Im Gegensatz dazu führt die Lösung der verknüpften Antwort eine Spliterator-Zusammensetzung durch, die ein neues Spliterator delegieren an Quellen-Spliteratoren erzeugt. Ich vermute, beide Ansätze haben Vorteile und ich bin mir nicht sicher, wie viel die OpenJDK-Implementierung verlieren würde, wenn man umgekehrt arbeitet.

    
Holger 11.07.2017, 16:08
quelle

Tags und Links