【发布时间】:2018-01-05 10:09:46
【问题描述】:
在他的一个视频中(关于 Scala 的惰性求值,即 lazy 关键字),Martin Odersky 展示了用于构造 Stream 的 cons 操作的以下实现:
def cons[T](hd: T, tl: => Stream[T]) = new Stream[T] {
def head = hd
lazy val tail = tl
...
}
所以tail 操作是使用语言的惰性求值功能简洁地编写的。
但实际上(在 Scala 2.11.7 中),tail 的实现并不那么优雅:
@volatile private[this] var tlVal: Stream[A] = _
@volatile private[this] var tlGen = tl _
def tailDefined: Boolean = tlGen eq null
override def tail: Stream[A] = {
if (!tailDefined)
synchronized {
if (!tailDefined) {
tlVal = tlGen()
tlGen = null
}
}
tlVal
}
双重检查锁定和两个 volatile 字段:这大致就是您在 Java 中实现线程安全惰性计算的方式。
所以问题是:
- Scala 的
lazy关键字在多线程情况下不提供任何“评估最大值一次”保证吗? - 在真正的
tail实现中使用的模式是在 Scala 中进行线程安全惰性求值的惯用方式吗?
【问题讨论】:
-
正在开发的新系列中的 FWIW the implementation 要简单得多。
-
@Jasper-M 这个新实现是否在多线程情况下提供了“评估最大值一次”的保证?如果是,它是如何实现的?对于愚蠢的问题,我很抱歉,但我是 Scala 的新手,我看不出该代码与 Martin 最初在幻灯片上展示的代码有任何主要区别。
-
我不知道。您必须询问开发人员。
-
我也不理解这个新实现,因为据我所知,每次访问方法 tail 时都会对其进行评估。
-
@L.Lampart 如果我没记错的话,唯一需要重新评估的是空值检查(因为该字段是易变的),这非常快。
标签: multithreading scala lazy-evaluation