Vraag Hoe de volgorde van verwerking in java8-streams te garanderen?


Ik wil lijsten verwerken binnen een XML java-object. Ik moet ervoor zorgen dat alle elementen worden verwerkt voordat ik ze ontvang.

Moet ik daarom bellen sequential op elke stream Ik gebruik? list.stream().sequential().filter().forEach()

Of is het voldoende om de stream gewoon te gebruiken zolang ik geen parallellisme gebruik? list.stream().filter().forEach()


85
2018-03-23 17:29


oorsprong


antwoorden:


U stelt de verkeerde vraag. U vraagt ​​naar sequential vs. parallel terwijl u items wilt verwerken in volgorde, dus je moet ernaar vragen bestellen. Als je een hebt bestelde streamen en uitvoeren van bewerkingen die garanderen dat de order behouden blijft, maakt het niet uit of de stream parallel of sequentieel wordt verwerkt; de implementatie zal de bestelling handhaven.

De geordende eigenschap verschilt van parallel vs sequentieel. Bijv. als je belt stream() op een HashSet de stream zal tijdens het bellen ongeordend zijn stream() op een List geeft een geordende stream terug. Merk op dat je kunt bellen unordered() om het bestelcontract vrij te geven en mogelijk de prestaties te verbeteren. Zodra de stream geen bestelling heeft, is er geen manier om de bestelling opnieuw te plaatsen. (De enige manier om een ​​niet-geordende stream om te zetten in een bestelling is om te bellen sortedde resulterende volgorde is echter niet noodzakelijk de oorspronkelijke volgorde).

Zie ook de "Bestellen" sectie van de java.util.stream pakket documentatie.

Om het onderhoud van de bestelling tijdens een gehele streambewerking te garanderen, moet u de documentatie van de bron van de stream, alle tussenliggende bewerkingen en de terminalbewerking bestuderen om te bepalen of ze de bestelling onderhouden (of dat de bron een bestelling heeft in de eerste plaats).

Dit kan heel subtiel zijn, b.v. Stream.iterate(T,UnaryOperator) creëert een geordende stream terwijl Stream.generate(Supplier) creëert een ongeordende stroom. Merk op dat je ook een veelgemaakte fout in je vraag hebt gemaakt als forEach  doet niet handhaaf de bestelling. Je moet gebruiken forEachOrdered als u de elementen van de stream in een gegarandeerde volgorde wilt verwerken.

Dus als je list in je vraag is inderdaad een java.util.List, het is stream() methode retourneert een bestelde streamen en filter zal de volgorde niet veranderen. Dus als je belt list.stream().filter() .forEachOrdered(), alle elementen worden sequentieel in volgorde verwerkt, terwijl voor list.parallelStream().filter().forEachOrdered() de elementen kunnen parallel worden verwerkt (bijvoorbeeld door het filter) maar de terminalactie zal nog steeds in de juiste volgorde worden aangeroepen (wat uiteraard het voordeel van parallelle uitvoering zal verminderen).

Als u bijvoorbeeld een bewerking zoals gebruikt

List<…> result=inputList.parallelStream().map(…).filter(…).collect(Collectors.toList());

de gehele bewerking kan baat hebben bij parallelle uitvoering, maar de resulterende lijst zal altijd in de juiste volgorde zijn, ongeacht of u een parallelle of sequentiële stream gebruikt.


223
2018-03-23 18:49



(sequentiële). filteren (). forEach () list.stream ().

zal de lijst altijd verwerken in de volgorde waarin de lijst zelf is besteld.

Maar als we het gebruiken

list.stream (). parallel ()

dan is de bestelling niet gegarandeerd voor de rest van de bewerkingen.


4
2017-12-05 12:51