Una característica útil de Scala es lazy val
, donde la evaluación de un val
se retrasa hasta que sea necesario (en el primer acceso).
Por supuesto, un lazy val
debe tener algunos gastos generales: en algún lugar, Scala debe realizar un seguimiento de si el valor ya se ha evaluado y si la evaluación debe estar sincronizada, ya que varios subprocesos pueden intentar acceder al valor por primera vez al mismo tiempo.
¿Cuál es exactamente el costo de un lazy val
? ¿Hay un indicador booleano oculto asociado con un lazy val
seguimiento si se ha evaluado o no, qué se sincroniza exactamente y hay más costos?
Además, supongamos que hago esto:
class Something {
lazy val (x, y) = { ... }
}
Es esto lo mismo que tener dos separadas lazy val
s x
y y
o qué tengo la cabeza una sola vez, para el par (x, y)
?
fuente
bitmap$0
campo es volátil en la implementación actual (2.8).Parece que el compilador organiza un campo int de mapa de bits de nivel de clase para marcar múltiples campos perezosos como inicializados (o no) e inicializa el campo de destino en un bloque sincronizado si el xor relevante del mapa de bits indica que es necesario.
Utilizando:
produce un código de bytes de muestra:
Los valores iniciados en tuplas como
lazy val (x,y) = { ... }
tienen almacenamiento en caché anidado a través del mismo mecanismo. El resultado de la tupla se evalúa y almacena en caché de forma perezosa, y un acceso de x o y activará la evaluación de la tupla. La extracción del valor individual de la tupla se realiza de forma independiente y perezosa (y en caché). Así que el código de doble ejemplificación anterior genera unax
,y
y unx$1
campo de tipoTuple2
.fuente
Con Scala 2.10, un valor vago como:
se compila en código de bytes que se parece al siguiente código Java:
Tenga en cuenta que el mapa de bits está representado por a
boolean
. Si agrega otro campo, el compilador aumentará el tamaño del campo para poder representar al menos 2 valores, es decir, como abyte
. Esto solo continúa para las grandes clases.Pero te preguntarás por qué esto funciona. Las memorias caché locales de subprocesos deben borrarse al ingresar un bloque sincronizado de modo que el
x
valor no volátil se vacíe en la memoria. Este artículo de blog da una explicación .fuente
Scala SIP-20 propone una nueva implementación de lazy val, que es más correcta pero ~ 25% más lenta que la versión "actual".
La implementación propuesta se ve así:
A junio de 2013, este SIP no ha sido aprobado. Espero que sea aprobado e incluido en una versión futura de Scala basada en la discusión de la lista de correo. En consecuencia, creo que sería prudente prestar atención a la observación de Daniel Spiewak :
fuente
He escrito una publicación con respecto a este tema https://dzone.com/articles/cost-laziness
En pocas palabras, la penalización es tan pequeña que en la práctica puedes ignorarla.
fuente
dado el bycode generado por scala para perezoso, puede sufrir un problema de seguridad de hilo como se menciona en el bloqueo de doble verificación http://www.javaworld.com/javaworld/jw-05-2001/jw-0525-double.html?page=1
fuente