Eine praktische Funktion von Scala ist lazy val
, dass die Auswertung von a val
verzögert wird, bis es notwendig ist (beim ersten Zugriff).
Natürlich lazy val
muss ein gewisser Overhead auftreten - irgendwo muss Scala nachverfolgen, ob der Wert bereits ausgewertet wurde, und die Auswertung muss synchronisiert werden, da möglicherweise mehrere Threads gleichzeitig versuchen, zum ersten Mal auf den Wert zuzugreifen.
Was genau kostet a lazy val
- gibt es ein verstecktes boolesches Flag, das mit a verknüpft ist lazy val
, um den Überblick zu behalten, ob es ausgewertet wurde oder nicht, was genau synchronisiert ist und ob weitere Kosten anfallen?
Angenommen, ich mache Folgendes:
class Something {
lazy val (x, y) = { ... }
}
Ist dies dasselbe wie zwei separate lazy val
s x
und y
oder bekomme ich den Overhead nur einmal für das Paar (x, y)
?
quelle
bitmap$0
Feld ist in der aktuellen Implementierung volatil (2.8).Es sieht so aus, als würde der Compiler ein Bitmap-Int-Feld auf Klassenebene einrichten, um mehrere Lazy-Felder als initialisiert (oder nicht) zu kennzeichnen, und das Zielfeld in einem synchronisierten Block initialisieren, wenn das relevante xor der Bitmap angibt, dass dies erforderlich ist.
Verwenden von:
erzeugt Beispielbytecode:
In Tupeln wie
lazy val (x,y) = { ... }
initialisierte Werte haben das verschachtelte Caching über denselben Mechanismus. Das Tupelergebnis wird träge ausgewertet und zwischengespeichert, und ein Zugriff von entweder x oder y löst die Tupelauswertung aus. Das Extrahieren des einzelnen Werts aus dem Tupel erfolgt unabhängig und träge (und zwischengespeichert). So dass der obige doppel Instanziierung Code generiert einx
,y
und einx$1
Feld vom TypTuple2
.quelle
Mit Scala 2.10 ein fauler Wert wie:
wird zu Bytecode kompiliert, der dem folgenden Java-Code ähnelt:
Beachten Sie, dass die Bitmap durch a dargestellt wird
boolean
. Wenn Sie ein weiteres Feld hinzufügen, vergrößert der Compiler das Feld so, dass mindestens 2 Werte dargestellt werden können, zbyte
. Dies gilt nur für große Klassen.Aber Sie fragen sich vielleicht, warum das funktioniert? Die threadlokalen Caches müssen beim Eingeben eines synchronisierten Blocks gelöscht werden, damit der nichtflüchtige
x
Wert in den Speicher geschrieben wird. Dieser Blog-Artikel gibt eine Erklärung .quelle
Scala SIP-20 schlägt eine neue Implementierung von Lazy Val vor, die korrekter, aber ~ 25% langsamer als die "aktuelle" Version ist.
Die vorgeschlagene Implementierung sieht folgendermaßen aus:
Bis Juni 2013 wurde dieses SIP nicht genehmigt. Ich gehe davon aus, dass es wahrscheinlich genehmigt und in eine zukünftige Version von Scala aufgenommen wird, basierend auf der Mailinglistendiskussion. Ich denke, Sie sollten die Beobachtung von Daniel Spiewak beachten :
quelle
Ich habe einen Beitrag zu diesem Thema geschrieben: https://dzone.com/articles/cost-laziness
Kurz gesagt, die Strafe ist so gering, dass Sie sie in der Praxis ignorieren können.
quelle
Angesichts des von scala for faul generierten Bycodes kann es zu Problemen mit der Thread-Sicherheit kommen, wie unter Überprüfen der Sperre http://www.javaworld.com/javaworld/jw-05-2001/jw-0525-double.html?page=1 angegeben
quelle