Um recurso útil do Scala é lazy val
que a avaliação de a val
é adiada até que seja necessária (no primeiro acesso).
Obviamente, é lazy val
necessário ter alguma sobrecarga - em algum lugar o Scala deve acompanhar se o valor já foi avaliado e a avaliação deve ser sincronizada, porque vários encadeamentos podem tentar acessar o valor pela primeira vez ao mesmo tempo.
Qual é exatamente o custo de um lazy val
- existe um sinalizador booleano oculto associado a um lazy val
para acompanhar se foi avaliado ou não, o que exatamente está sincronizado e há mais custos?
Além disso, suponha que eu faça isso:
class Something {
lazy val (x, y) = { ... }
}
É o mesmo que ter dois lazy val
s separados x
e y
ou recebo a sobrecarga apenas uma vez para o par (x, y)
?
fonte
bitmap$0
campo é volátil na implementação atual (2.8).Parece que o compilador organiza um campo int de bitmap em nível de classe para sinalizar vários campos preguiçosos como inicializados (ou não) e inicializa o campo de destino em um bloco sincronizado se o xor relevante do bitmap indicar que é necessário.
Usando:
produz bytecode de amostra:
Valores inicializados em tuplas, como o
lazy val (x,y) = { ... }
cache aninhado pelo mesmo mecanismo. O resultado da tupla é avaliado e armazenado em cache preguiçosamente, e um acesso de x ou y acionará a avaliação da tupla. A extração do valor individual da tupla é feita de forma independente e lenta (e armazenada em cache). Assim, o código double-instanciação acima gera umx
,y
e umx$1
campo de tipoTuple2
.fonte
Com o Scala 2.10, um valor lento como:
é compilado para código de bytes que se assemelha ao seguinte código Java:
Observe que o bitmap é representado por um
boolean
. Se você adicionar outro campo, o compilador aumentará o tamanho do campo para poder representar pelo menos 2 valores, como abyte
. Isso acontece em grandes classes.Mas você pode se perguntar por que isso funciona? Os caches locais do encadeamento devem ser limpos ao inserir um bloco sincronizado, para que o
x
valor não volátil seja liberado na memória. Este artigo do blog fornece uma explicação .fonte
O Scala SIP-20 propõe uma nova implementação de lazy val, que é mais correta, mas ~ 25% mais lenta que a versão "atual".
A implementação proposta se parece com:
Em junho de 2013, este SIP não foi aprovado. Espero que seja aprovado e incluído em uma versão futura do Scala com base na discussão da lista de discussão. Consequentemente, acho que seria sensato atender à observação de Daniel Spiewak :
fonte
Escrevi um post sobre esse problema https://dzone.com/articles/cost-laziness
Em poucas palavras, a penalidade é tão pequena que, na prática, você pode ignorá-la.
fonte
dado o bycode gerado pelo scala for preguiçoso, ele pode sofrer um problema de segurança de thread, conforme mencionado no bloqueio de verificação dupla http://www.javaworld.com/javaworld/jw-05-2001/jw-0525-double.html?page=1
fonte