Performance 矢量或可变列表/ListBuffer,以提高性能

Performance 矢量或可变列表/ListBuffer,以提高性能,performance,scala,playframework-2.0,immutability,Performance,Scala,Playframework 2.0,Immutability,如果这是一个重复的道歉-我做了一些搜索,并没有完全找到我需要的 我们的应用程序中有一个性能关键的部分,它将输入数据的Play 2.0枚举器(可以被认为是流)转换为列表(或类似)。我们将使用枚举器上的fold方法,问题是最有效的方法是什么。(我将在代码中使用Stream而不是Enumerator,但想法应该是一样的。) 因此,问题本质上是,在性能关键代码中,重复附加到不可变的向量与重复附加到可变的可变列表或列表缓冲区相比如何?我们只抛出了List,因为我们需要O(1)追加(而不是预加)。但是可变数

如果这是一个重复的道歉-我做了一些搜索,并没有完全找到我需要的

我们的应用程序中有一个性能关键的部分,它将输入数据的Play 2.0
枚举器(可以被认为是
)转换为
列表
(或类似)。我们将使用
枚举器
上的
fold
方法,问题是最有效的方法是什么。(我将在代码中使用
Stream
而不是
Enumerator
,但想法应该是一样的。)


因此,问题本质上是,在性能关键代码中,重复附加到不可变的
向量
与重复附加到可变的
可变列表
列表缓冲区
相比如何?我们只抛出了
List
,因为我们需要
O(1)
追加(而不是预加)。但是可变数据结构在性能或垃圾收集方面给我们带来了什么好处吗?

您最好使用
ArrayBuffer
。在我的机器上,每秒可获得以下数量的附件:

preallocated Array[Int]    -- 830M
resized (x2) Array[Int]    -- 263M
Vector.newBuilder + result -- 185M
mutable.ArrayBuffer        -- 125M
mutable.ListBuffer         -- 100M
mutable.MutableList        --  71M
immutable.List + reverse   --  68M
immutable.Vector           --   8M

我假设您并不总是只存储int,而且您希望所有集合都没有额外的包装,因此
ArrayBuffer
是性能最好的解决方案,只要您只需要附加到一端。列表支持双向添加,并且具有可比性。相比之下,Vector的速度非常慢——只有在您可以利用大量数据共享或一次性创建的情况下才能使用它(请参见
Vector.newBuilder
result,这是一个非常棒的数据结构,用于访问、迭代、创建和保存更新,而不是一直更新).

为什么不直接使用
toList
?如果不清楚,很抱歉-该应用程序使用Play 2.0中的枚举器,因此有点不同。我认为在示例代码中使用流会更简单,但我想这会让人有点困惑。。。我该如何解决这个问题?部分是我的错-我没有注意到你提到了
。在问题中提到这是一个Play 2.0 EnumeratorTypo就足够了
val incoming:String[Int]
很好地描述了这两种数据结构的工作方式,似乎与您的用例有关。“resized(x2)Array[Int]”和
ArrayBuffer
之间的差异让我感到惊讶,因为后者基于
resizeablearray
,后者使用相同的调整策略。你知道是什么导致了速度减慢吗?@paradigmatic-主要是
Int
的装箱。在我的例子中
Int
的使用过于简单。此外,我们确实需要将其转换为
列表
,或者至少在最后转换为一些
序列
Vector.newBuilder
ListBuffer
听起来最好。@RexKerr请问您是如何创建性能测试输出的?自定义代码还是公共代码?@BAR-我已经不记得我做过什么了。我总是做这种事。我可能使用了我自己的基准测试工具百里香,但我可能使用了卡尺。
preallocated Array[Int]    -- 830M
resized (x2) Array[Int]    -- 263M
Vector.newBuilder + result -- 185M
mutable.ArrayBuffer        -- 125M
mutable.ListBuffer         -- 100M
mutable.MutableList        --  71M
immutable.List + reverse   --  68M
immutable.Vector           --   8M