use*_*123 7 scala lazy-evaluation micro-optimization
我在JAXMag的Scala特殊问题中遇到了以下代码:
package com.weiglewilczek.gameoflife
case class Cell(x: Int, y: Int) {
override def toString = position
private lazy val position = "(%s, %s)".format(x, y)
}
Run Code Online (Sandbox Code Playgroud)
lazy val上述代码中的使用是否比下面的代码提供了更多的性能?
package com.weiglewilczek.gameoflife
case class Cell(x: Int, y: Int) {
override def toString = "(%s, %s)".format(x, y)
}
Run Code Online (Sandbox Code Playgroud)
或者只是一个不必要的优化案例?
Dav*_*ith 19
关于延迟val的一件事是,虽然它们只计算一次,但每次访问它们都受到双重检查锁定包装的保护.这对于防止两个不同的线程同时尝试使用热闹的结果来初始化值是必要的.现在,双重检查锁定是非常有效的(现在它实际上在JVM中工作),并且在大多数情况下不需要锁获取,但是比简单的值访问有更多的开销.
另外(有些显而易见),通过缓存对象的字符串表示,您可以明确地权衡CPU周期,因为内存使用量可能会大幅增加."def"版本中的字符串可以被垃圾收集,而"lazy val"版本中的字符串则不会.
最后,正如性能问题一样,基于理论的假设在没有基于事实的基准测试的情况下几乎没有任何意义.如果没有剖析,你永远不会知道,所以不妨试试看看.
ret*_*nym 13
toString可以用a直接覆盖lazy val.
scala> case class Cell(x: Int, y: Int) {
| 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))
Run Code Online (Sandbox Code Playgroud)
请注意,a def可能不会覆盖val- 您只能在子类中使成员更稳定.
根据定义,案例类是不可变的。toString 返回的任何值本身也是不可变的。因此,通过利用惰性值来“缓存”该值是有意义的。另一方面,提供的 toString 实现的作用与所有案例类提供的默认 toString 没什么区别。如果普通案例类 toString 在下面使用了惰性 val,我不会感到惊讶。