Использование lazy val для кэширования строковых представлений

Я обнаружил следующий код в специальном выпуске Scala от JAXMag:

package com.weiglewilczek.gameoflife

case class Cell(x: Int, y: Int) {
  override def toString = position
  private lazy val position = "(%s, %s)".format(x, y)
}

Использует лиlazy val в приведенном выше коде обеспечить значительно большую производительность, чем следующий код?

package com.weiglewilczek.gameoflife

case class Cell(x: Int, y: Int) {
  override def toString = "(%s, %s)".format(x, y)
}

Или это просто случай ненужной оптимизации?

 user38215707 окт. 2010 г., 19:00
Просто чтобы вы знали, вы можете получить тот же формат строки, вызвав(x, y).toString
 wheaties07 окт. 2010 г., 17:32
Ленивый должен оттолкнуть вычисление значения, пока оно не будет вызвано. Впрочем, хороший вопрос. Создает ли объект объект для оценки?

Ответы на вопрос(5)

toString может быть напрямую переопределенlazy val.

     |   override lazy val toString = {println("here"); "(%s, %s)".format(x, y)}
     | }
defined class Cell

scala> {val c = Cell(1, 2); (c.toString, c.toString)}
here
res0: (String, String) = ((1, 2),(1, 2))

Обратите внимание, чтоdef не может переопределитьval - вы можете только сделать членов более стабильными в подклассе.

 missingfaktor07 окт. 2010 г., 18:39
+1, не зналdef может быть отмененоlazy val, :)

возвращаемое toString, само будет неизменным. Таким образом, имеет смысл «кэшировать» это значение, используя ленивый val. С другой стороны, предоставленная реализация toString делает немного больше, чем стандартная toString, предоставляемая всеми классами case. Я не удивлюсь, если под классом ванильного класса toString используется ленивый val.

 Viktor Klang08 окт. 2010 г., 11:04
Неизменным по определению? scala> case class Foo (var x: Int) определяет класс Foo
 Max A.09 окт. 2010 г., 19:47
Не зналvar Модификатор может быть использован для членов класса данных дела. Я должен был сказать: «Класс случая, указанный в вопросе, является неизменным по определению», хотя я все еще думаю, что то, что вы сделали, - это чистое зло.

что, хотя они рассчитываются только один раз, каждый доступ к ним защищен двойной проверкой блокировочной оболочки. Это необходимо для предотвращения одновременной инициализации значения двумя разными потоками с веселыми результатами. Теперь двойная проверка блокировки довольно эффективна (теперь, когда она действительно работает в JVM), и в большинстве случаев не потребует получения блокировки, но она требует больше затрат, чем простой доступ к значениям.

Кроме того (и несколько очевидно), кэшируя строковое представление вашего объекта, вы явно тратите деньги на циклы ЦП для возможного значительного увеличения использования памяти. Строки в версии «def» можно собирать мусором, а строки в версии «lazy val» - нет.

Наконец, как всегда в случае с вопросами производительности, основанные на теории гипотезы почти ничего не значат без основанного на фактах сопоставления. Вы никогда не узнаете наверняка без профилирования, так что можете попробовать и посмотреть.

position будет рассчитываться только один раз, по запросу, [когда | если]toString метод называется. Во втором фрагменте,toString Тело будет пересматриваться каждый раз, когда вызывается метод. При условииx а такжеy не может быть изменено, это бессмысленно, иtoString значение должно быть сохранено.

микро-оптимизация для меня. JVM достаточно способна позаботиться о таких случаях.

 Dave Griffith07 окт. 2010 г., 18:02
В JVM нет абсолютно ничего, что запоминало бы результаты методов, подобные этим, за пределами локальной области (т. Е. Если дважды вызывать .toString в одном и том же методе, у JVM есть вероятность кэширования простых методов). Постоянное кэширование таких результатов - это путь вне его области действия, что хорошо, поскольку (в данном случае) автоматическое запоминание приведет к значительному увеличению объема памяти

Ваш ответ на вопрос