Одна удобная особенность Scala заключается в том lazy val
, что оценка a val
откладывается до тех пор, пока это необходимо (при первом доступе).
Конечно, a lazy val
должен иметь некоторые издержки - где-то Scala должен отслеживать, было ли значение уже оценено, и оценка должна быть синхронизирована, потому что несколько потоков могут пытаться получить доступ к значению в первый раз одновременно.
Какова стоимость a lazy val
- есть ли скрытый логический флаг, связанный с a, lazy val
чтобы отслеживать, был ли он оценен или нет, что именно синхронизируется и есть ли какие-либо дополнительные затраты?
Кроме того, предположим, что я делаю это:
class Something {
lazy val (x, y) = { ... }
}
Это то же самое , как иметь два отдельных lazy val
сек x
и y
или я получаю накладные расходы только один раз, для пары (x, y)
?
источник
bitmap$0
поле в текущей реализации изменчиво (2.8).Похоже, что компилятор организует поле int для битовой карты на уровне класса, чтобы пометить несколько ленивых полей как инициализированные (или нет), и инициализирует целевое поле в синхронизированном блоке, если соответствующий xor битовой карты указывает на необходимость.
С помощью:
производит образец байт-кода:
Значения, инициализированные в кортежах, например,
lazy val (x,y) = { ... }
имеют вложенное кэширование через тот же механизм. Результат кортежа лениво оценивается и кэшируется, и доступ к x или y инициирует оценку кортежа. Извлечение индивидуального значения из кортежа выполняется независимо и лениво (и кэшируется). Таким образом , приведенный выше код дважды Инстанциация генерируетx
,y
и вx$1
поле типаTuple2
.источник
В Scala 2.10 ленивое значение, например:
скомпилирован в байтовый код, который похож на следующий код Java:
Обратите внимание, что растровое изображение представлено как
boolean
. Если вы добавите другое поле, компилятор увеличит размер поля, чтобы иметь возможность представлять как минимум 2 значения, то есть какbyte
. Это просто продолжается для огромных классов.Но вы можете спросить, почему это работает? При входе в синхронизированный блок локальные кэши потоков должны быть очищены, чтобы энергонезависимое
x
значение сбрасывалось в память. Эта статья в блоге дает объяснение .источник
Scala SIP-20 предлагает новую реализацию lazy val, которая более корректна, но примерно на 25% медленнее, чем «текущая» версия.
В предлагаемой реализации выглядит следующим образом :
По состоянию на июнь 2013 года этот SIP не был одобрен. Я ожидаю, что он, скорее всего, будет одобрен и включен в будущую версию Scala на основе обсуждения в списке рассылки. Следовательно, я думаю, что было бы разумно прислушаться к замечаниям Даниэля Спивака :
источник
Я написал сообщение по этому вопросу https://dzone.com/articles/cost-laziness
В двух словах, штраф настолько мал, что на практике вы можете его игнорировать.
источник
учитывая код, созданный scala для lazy, он может столкнуться с проблемой безопасности потоков, как упомянуто в двойной проверке блокировки http://www.javaworld.com/javaworld/jw-05-2001/jw-0525-double.html?page=1.
источник