© Excellent backgrounds/Shutterstock.com
Java Magazin
Effective Java: Teil 13

Java 8: Stream Performance

Wir wollen uns in diesem Artikel dem Thema Stream Performance zuwenden. Es geht zum einen darum, ob sequenzielle Streams schneller oder langsamer sind als for-Schleifen. Außerdem schauen wir uns an, um wie viel parallele Streams schneller sind als sequenzielle Streams und von welchen Kriterien der Geschwindigkeitsunterschied abhängt.

Angelika Langer, Klaus Kreft


Nachdem wir uns jetzt schon in einigen Artikeln mit den Streams beschäftigt haben, stellen wir nun die Frage: Wie sieht es eigentlich mit der Performance von Streams aus? Anfangen wollen wir mit dem Performancevergleich von Stream und for-Schleife.

Einfache Funktionalität

Beginnen wir mit einem einfachen Beispiel. Wir wollen in einem int-Array mit 500 000 ganzzahligen Zufallszahlen die größte Zahl suchen. Dies ist der Code für die Lösung mit einer for-Schleife:

int[] a = ints;int e = ints.length;int m = Integer.MIN_VALUE; for (int i = 0; i m) m = a[i];

und dies der Code für die Lösung mit einem sequenziellen IntStream:

int m = Arrays.stream(ints) .reduce(Integer.MIN_VALUE, Math::max);

Wir haben hier bewusst die reduce()-Methode anstelle der max()-Methode genutzt, weil max() ein OptionalInt zurückliefert. Das erfordert die Konstruktion eines OptionalInt-Objekts, die bei Verwendung von reduce() entfallen kann. Die Lösung mit reduce() ist deshalb eher vergleichbar mit dem Code der for-Schleife als mit einer Lösung via max(). Das Ergebnis unserer Performancemessung ist:

for-Schleife: 0.36 msseq. Stream: 5.35 ms

Das Ergebnis sieht ziemlich eindeutig aus: Die for-Schleife ist knapp 15-mal schneller als der sequenzielle Stream. Bevor wir dieses Ergebnis zu einem „Streams-sind-total-langsam-Statement“ verallgemeinern wollen, schauen wir uns an, wie das Ganze aussieht, wenn wir als unterliegende Sequenz anstelle eines int-Arrays eine ArrayList verwenden. Der Code für die for-Schleife ist nun:

int m = Integer.MIN_VALUE;for (int i : myList) if (i > m) m = i;

und der Code für die sequenzielle Streamlösung ist:

int m = myList.stream() .reduce(Integer.MIN_VALUE, Math::max);

Mit folgendem Ergebnis:

ArrayList, for-Schleife: 6.55 msArrayList, seq. Stream: 8.33 ms

Auch hier ist wieder die for-Schleife schneller, aber die Unterschiede sind nicht mehr so signifikant. Der Geschwindigkeitsvorteil beträgt nur noch das 1,27-fache. Woran liegt es? Der Speicherzugriff bei der Iteration über die ArrayList ist deutlich aufwändiger als bei einem int-Array. Dies verursacht hohe Grundkosten. Deshalb fällt der Performancevorteil der for-Schleife gegenüber dem sequenziellen Stream geringer aus, denn die teuren Speicherzugriffe überdecken den Unterschied zwischen for-Schleife und Stream.

Neben den Kosten der Iteration spielen aber auch die Kosten der auf die Sequenzelemente anzuwendenden Funktionalität eine Rolle. In un...

Java Magazin
Effective Java: Teil 13

Java 8: Stream Performance

Wir wollen uns in diesem Artikel dem Thema Stream Performance zuwenden. Es geht zum einen darum, ob sequenzielle Streams schneller oder langsamer sind als for-Schleifen. Außerdem schauen wir uns an, um wie viel parallele Streams schneller sind als sequenzielle Streams und von welchen Kriterien der Geschwindigkeitsunterschied abhängt.

Angelika Langer, Klaus Kreft


Nachdem wir uns jetzt schon in einigen Artikeln mit den Streams beschäftigt haben, stellen wir nun die Frage: Wie sieht es eigentlich mit der Performance von Streams aus? Anfangen wollen wir mit dem Performancevergleich von Stream und for-Schleife.

Einfache Funktionalität

Beginnen wir mit einem einfachen Beispiel. Wir wollen in einem int-Array mit 500 000 ganzzahligen Zufallszahlen die größte Zahl suchen. Dies ist der Code für die Lösung mit einer for-Schleife:

int[] a = ints;int e = ints.length;int m = Integer.MIN_VALUE; for (int i = 0; i m) m = a[i];

und dies der Code für die Lösung mit einem sequenziellen IntStream:

int m = Arrays.stream(ints) .reduce(Integer.MIN_VALUE, Math::max);

Wir haben hier bewusst die reduce()-Methode anstelle der max()-Methode genutzt, weil max() ein OptionalInt zurückliefert. Das erfordert die Konstruktion eines OptionalInt-Objekts, die bei Verwendung von reduce() entfallen kann. Die Lösung mit reduce() ist deshalb eher vergleichbar mit dem Code der for-Schleife als mit einer Lösung via max(). Das Ergebnis unserer Performancemessung ist:

for-Schleife: 0.36 msseq. Stream: 5.35 ms

Das Ergebnis sieht ziemlich eindeutig aus: Die for-Schleife ist knapp 15-mal schneller als der sequenzielle Stream. Bevor wir dieses Ergebnis zu einem „Streams-sind-total-langsam-Statement“ verallgemeinern wollen, schauen wir uns an, wie das Ganze aussieht, wenn wir als unterliegende Sequenz anstelle eines int-Arrays eine ArrayList verwenden. Der Code für die for-Schleife ist nun:

int m = Integer.MIN_VALUE;for (int i : myList) if (i > m) m = i;

und der Code für die sequenzielle Streamlösung ist:

int m = myList.stream() .reduce(Integer.MIN_VALUE, Math::max);

Mit folgendem Ergebnis:

ArrayList, for-Schleife: 6.55 msArrayList, seq. Stream: 8.33 ms

Auch hier ist wieder die for-Schleife schneller, aber die Unterschiede sind nicht mehr so signifikant. Der Geschwindigkeitsvorteil beträgt nur noch das 1,27-fache. Woran liegt es? Der Speicherzugriff bei der Iteration über die ArrayList ist deutlich aufwändiger als bei einem int-Array. Dies verursacht hohe Grundkosten. Deshalb fällt der Performancevorteil der for-Schleife gegenüber dem sequenziellen Stream geringer aus, denn die teuren Speicherzugriffe überdecken den Unterschied zwischen for-Schleife und Stream.

Neben den Kosten der Iteration spielen aber auch die Kosten der auf die Sequenzelemente anzuwendenden Funktionalität eine Rolle. In un...

Neugierig geworden?


    
Loading...

Angebote für Teams

Für Firmen haben wir individuelle Teamlizenzen. Wir erstellen Ihnen gerne ein passendes Angebot.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang