Scala-Seq与列表性能
所以我有点困惑。我有一段Scala代码(确切的代码并不那么重要)。我把我所有的方法都写下来取Seq[T]。这些方法大多是尾部递归的,并使用Seq[T]作为累加器,最初像Seq()一样输入。有趣的是,当我用具体的List()实现交换所有签名时,我发现性能提高了三倍 Seq的默认实现实际上是一个不可变的列表,这不是吗?如果是这样的话,到底发生了什么 调用Scala-Seq与列表性能,scala,jvm,scala-collections,Scala,Jvm,Scala Collections,所以我有点困惑。我有一段Scala代码(确切的代码并不那么重要)。我把我所有的方法都写下来取Seq[T]。这些方法大多是尾部递归的,并使用Seq[T]作为累加器,最初像Seq()一样输入。有趣的是,当我用具体的List()实现交换所有签名时,我发现性能提高了三倍 Seq的默认实现实际上是一个不可变的列表,这不是吗?如果是这样的话,到底发生了什么 调用Seq(1,2,3)和调用List(1,2,3)都会导致1::2::3::Nil。该方法只是一种非常通用的方法,如下所示: def apply[A]
Seq(1,2,3)
和调用List(1,2,3)
都会导致1::2::3::Nil
。该方法只是一种非常通用的方法,如下所示:
def apply[A](elems: A*): CC[A] = {
if (elems.isEmpty) empty[A]
else {
val b = newBuilder[A]
b ++= elems
b.result()
}
}
def result: List[A] = toList
/** Converts this buffer to a list. Takes constant time. The buffer is
* copied lazily, the first time it is mutated.
*/
override def toList: List[A] = {
exported = !isEmpty
start
}
newBuilder
是这里最重要的东西。与会代表:
因此Seq
的Builder
是一个可变的.ListBuffer
。Seq
通过将元素附加到空的ListBuffer
然后调用它来构造,其实现方式如下:
def apply[A](elems: A*): CC[A] = {
if (elems.isEmpty) empty[A]
else {
val b = newBuilder[A]
b ++= elems
b.result()
}
}
def result: List[A] = toList
/** Converts this buffer to a list. Takes constant time. The buffer is
* copied lazily, the first time it is mutated.
*/
override def toList: List[A] = {
exported = !isEmpty
start
}
List
还有一个ListBuffer
作为Builder
。它经历了一个稍微不同但相似的建造过程。无论如何,这不会有很大的区别,因为我假设您的大多数算法都是将内容预先添加到Seq
,而不是一直调用Seq.apply(…)
。即使你做到了,也不会有多大区别
如果看不到具有该行为的代码,就很难说出导致您看到的行为的原因。您是否有一些代码可以证明这一点?
Seq
默认实现实际上是一个ArrayBuffer
,而不是一个列表
。您拥有的用例实际上是为List
s定制的,因为它们是尾部递归实现的。这会导致如此巨大的性能差异吗?默认Seq
的默认实现是List
。您可以展示代码以及如何调用它吗?根据您的假设,Seq.apply只是一个列表,并且没有太大区别,您实际上可以这样做,对不对:val sequence:LinearSeq[]=Seq(),这应该相应地起作用,因为Seq是一个列表,而List使用LinearSeq特性。但是它不起作用,因此,它关系到如何构造序列,特别是当您需要有效的尾部访问或尾部递归操作(即,对序列执行迭代的方法)时Seq()。这就是为什么不能将其分配给LinearSeq
类型的变量。评估Seq(1).getClass
并查看您得到了什么。但要清楚,我确实同意,如果您想要列表的性能特征,最好只使用List
。我刚刚与调试器进行了检查。我假设Seq只使用ListBuffer构建序列,而不处理序列,并使用Traversable中优化程度较低的操作,等等,但事实证明它实际上是从列表及其特征中访问优化的方法。就所有意图和目的而言,您完全正确地声明List.apply可替换为Seq.apply。您应该始终使用三种Seq特征的apply方法。没有任何性能偏差的解释。