multithreading - Scala Stream尾部懒惰和同步

标签 multithreading scala lazy-evaluation

在他的一个视频中(关于 Scala 的惰性求值,即 lazy 关键字),Martin Odersky 展示了 cons 的以下实现用于构造 Stream 的操作:

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
}

双重检查锁定和两个 v​​olatile 字段:这大致是您在 Java 中实现线程安全延迟计算的方式。

所以问题是 :
  • 没有 lazy Scala 的关键字在多线程情况下提供任何“评估最大一次”保证?
  • 是不是真实使用的图案tail实现在 Scala 中进行线程安全的惰性求值的惯用方法?
  • 最佳答案

    Doesn't lazy keyword of Scala provide any 'evaluated maximum once' guarantee in a multi-threaded case?



    是的,正如其他人所说的那样。

    Is the pattern used in real tail implementation an idiomatic way to do a thread-safe lazy evaluation in Scala?



    编辑:

    我想我有实际的答案,为什么不lazy val . Stream具有面向公众的 API 方法,例如 hasDefinitionSize继承自 TraversableOnce .为了知道是否Stream有一个有限的大小不是,我们需要一种检查方法而不具体化底层 Stream尾部。自 lazy val实际上并没有暴露底层,我们不能这样做。

    这是由 SI-1220 支持的

    为了加强这一点,@Jasper-M 指出新的 LazyList稻草人中的 api(Scala 2.13 集合改造)不再有这个问题,因为整个集合层次结构已经重新设计,不再有这样的问题。

    性能相关问题

    我会说“这取决于”您从哪个角度看待这个问题。从 LOB 的角度来看,我肯定会说 lazy val为了实现的简洁和清晰。但是,如果您从 Scala 集合库作者的角度来看它,事情就会开始变得不同。这样想,您正在创建一个可能被许多人使用并在世界各地的许多机器上运行的库。这意味着您应该考虑每个结构的内存开销,尤其是当您自己创建这样一个基本数据结构时。

    我这样说是因为当你使用 lazy val 时,按照设计,您会生成一个额外的 Boolean标记值是否已初始化的字段,我假设这是库作者旨在避免的。 Boolean的大小在 JVM 上当然依赖于 VM,即使是一个字节也是需要考虑的,尤其是当人们生成大 Stream 时。 s 的数据。同样,这绝对不是我通常会考虑的事情,绝对是对内存使用的微优化。

    我认为性能是这里的关键点之一的原因是 SI-7266它修复了 Stream 中的内存泄漏。请注意跟踪字节码以确保在生成的类中没有保留额外的值是多么重要。

    实现上的区别在于tail的定义是否被初始化是一个检查生成器的方法实现:
    def tailDefined: Boolean = tlGen eq null
    

    而不是类上的字段。

    关于multithreading - Scala Stream尾部懒惰和同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48111320/

    相关文章:

    java - java中允许特定数量的用户访问某个方法

    android - RxJava Subject 在不正确的调度程序上发出

    c# - 将并发字典保存线程不安全的集合是否需要在C#中锁定

    scala - Apache POI : Why Is a Row Missing When I use shiftRows?

    scala - 如何在 Scala 中为更高级的类型使用通配符?

    d - D 中的无限数据结构

    c# - 不同线程上的可停止控制台读取

    scala - Spark 流式 Elasticsearch 依赖项

    properties - 惰性的 Kotlin 委托(delegate)属性是线程本地的

    haskell - Haskell 有 `foldr` 的急切版本吗?