【问题标题】:Scala advantages of Seq.newBuilder over Seq varsSeq.newBuilder 相对于 Seq vars 的 Scala 优势
【发布时间】:2020-07-15 18:18:23
【问题描述】:

目前在我的应用程序中,我使用var fooSeq: Seq[Foo] = Seq.empty,然后使用:+ 附加项目。我知道这可能会导致多线程问题和潜在的竞争条件,但到目前为止还没有任何问题。

我最近发现了Seq.newBuilder(),似乎这可能是使用 Scala 序列的首选方式。我想知道性能优势是否优于使用 vars,以及它可能带来的任何其他类型的好处

【问题讨论】:

  • 所有构建器都将是命令式和增量式构建集合的最快方式。但是,除非包含在单个方法的范围内,否则它们的可变性可能是危险的。另外,另一个问题是builder不是collection,所以你必须调用result()(我相信是这样调用的) i> 最后,所以你不能使用中间步骤;您可以在 var 中使用不可变集合。

标签: scala scala-collections


【解决方案1】:

一般来说,如果您关心线程安全,那么一种常见的方法是使用 Java 的 AtomicReference 来包装您的可变变量,如下所示:

val fooSeq: AtomicReference[Seq[Foo]] = new AtomicReference(Seq.empty)

如果您需要中间结果而不是使用 Builder,那将是更好的方法。

如果您不需要中间结果,那么构建器通常会更好。 (尽管 Luis Miguel 在评论中提到 Builders 在内部是可变的,不一定是线程安全的)

第三种选择是使用 Scala 的 collections 中的可变数据结构:https://docs.scala-lang.org/overviews/collections/performance-characteristics.html

您可能对:MutableList 感兴趣,但是如果这是一个问题,这仍然需要 AtomicReference 包装以确保线程安全。有一些数据结构本身是线程安全的,例如 TrieMap,这些数据结构在 collections.concurrent 中可用

【讨论】:

  • “Scala 的一个奇怪之处在于它们可以声明为 val”,这有什么奇怪的? - “并且这些在 collections.concurrent 中可用”,不应该使用 AFAIK collections.concurrent,而是回退到 Java 的。
  • 在 haskell 中,您需要将可变值包装在类似 State 的 Monad 中以实现可变性。 "val" 对不变性非常具有误导性。
  • val 表示引用是不可变的,即变量的值不能改变。如果该值在内部是可变的,则超出了该范围。
  • 当然,这是对 Scala 中“val/var”的更准确描述,但是“val”通常只是被描述为“不可变”而没有那个警告。
  • 感谢你们两位的cmets,从你们两位那里学到了一些东西。我决定 Seq.newBuilder() 对我不利,因为我确实需要在我的 seq 上执行中间步骤,Fabian 我将研究您提供的一些资源。谢谢!
猜你喜欢
  • 2017-03-19
  • 2010-12-23
  • 2015-07-23
  • 2011-02-26
  • 1970-01-01
  • 2012-05-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多