Ich habe den folgenden Code in JAXMags Scala-Sonderausgabe gefunden:
%Vor% Bietet die Verwendung von lazy val
im obigen Code erheblich mehr Leistung als der folgende Code?
Oder ist es nur eine unnötige Optimierung?
Eine Sache, die bei Lazy Vals zu beachten ist, besteht darin, dass sie zwar nur einmal berechnet werden, aber jeder Zugriff auf sie durch einen doppelt überprüften Sperr-Wrapper geschützt ist. Dies ist erforderlich, um zu verhindern, dass zwei verschiedene Threads versuchen, den Wert gleichzeitig mit lustigen Ergebnissen zu initialisieren. Die doppelte Überprüfung ist nun ziemlich effizient (da sie nun in der JVM funktioniert) und erfordert in den meisten Fällen keine Sperrenerfassung, aber es gibt mehr Aufwand als ein einfacher Wertzugriff.
Zusätzlich (und etwas offensichtlich), indem Sie die Zeichenfolgendarstellung Ihres Objekts zwischenspeichern, gehen Sie explizit CPU-Zyklen für möglicherweise große Zunahmen in der Speichernutzung aus. Die Zeichenfolgen in der "def" -Version können Garbage-collected sein, während die in der "lazy val" -Version nicht enthalten sind.
Schliesslich, wie immer bei Leistungsfragen, bedeuten theoriebasierte Hypothesen fast nichts ohne faktenbasiertes Benchmarking. Sie werden nie sicher wissen, ohne Profiling, also könnte es auch versuchen und sehen.
Im ersten Ausschnitt wird position
nur einmal berechnet, bei Bedarf wird die Methode toString
aufgerufen. Im zweiten Snippet wird toString
body bei jedem Aufruf der Methode erneut ausgewertet. Da x
und y
nicht geändert werden können, ist es sinnlos, und toString
value sollte gespeichert werden.
Fallklassen sind per Definition unveränderbar. Jeder von toString zurückgegebene Wert wird ebenfalls unveränderlich sein. Daher ist es sinnvoll, diesen Wert durch Verwendung eines Lazy Val im Wesentlichen zu "cachen". Auf der anderen Seite führt die bereitgestellte toString-Implementierung wenig mehr als den Standardwert toString aus, der von allen Fallklassen bereitgestellt wird. Ich wäre nicht überrascht, wenn eine Vanilla-Case-Klasse toString ein Lazy Val darunter verwendet.
Sieht für mich wie eine Mikrooptimierung aus. JVM ist in der Lage, sich um solche Fälle zu kümmern.
Tags und Links scala lazy-evaluation micro-optimization