Scala Stream与Scala List和Scala Sequence之间有什么区别

时间:2018-05-23 10:00:51

标签: scala scala-collections

我有一个场景,我以对象流的形式获取数据库数据。 在将其转换为Object序列时,需要时间。 我正在寻找替代方案,花费更少的时间。

1 个答案:

答案 0 :(得分:7)

快速回答: Scala流已经是 Scala序列,根本不需要转换。下面进一步说明......

Scala序列scala.collection.Seq)只是以特定顺序存储元素序列的任何集合(排序是任意的,但元素顺序一旦定义就不会改变)

Scala列表scala.collection.immutable.List)是Seq的子类,也是scala.collection.Seq的默认实现。也就是说,Seq(1, 2, 3)实现为List(1, 2, 3)List是严格的,因此列表上的任何操作都会一个接一个地处理所有元素,然后才能执行另一个操作。

例如,请考虑 Scala REPL 中的此示例:

$ scala
Welcome to Scala 2.12.5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_171).
Type in expressions for evaluation. Or try :help.

scala> val xs = List(1, 2, 3)
xs: List[Int] = List(1, 2, 3)

scala> xs.map {x =>
     |   val newX = 2 * x
     |   println(s"Mapping value $x to $newX...")
     |   newX
     | }.foreach {x =>
     |   println(s"Printing value $x")
     | }
Mapping value 1 to 2...
Mapping value 2 to 4...
Mapping value 3 to 6...
Printing value 2
Printing value 4
Printing value 6

注意如何映射每个值,在之前创建新列表(List(2, 4, 6)),打印出新列表的任何值?

Scala流scala.collection.immutable.Stream)也是Seq的子类,但它是 lazy (或非严格),意味着只有在需要时才会获取流中的下一个值。它通常被称为懒惰列表

为了说明StreamList之间的区别,让我们重做一下这个例子:

scala> val xs = Stream(1, 2, 3)
xs: scala.collection.immutable.Stream[Int] = Stream(1, ?)

scala> xs.map {x =>
     |   val newX = 2 * x
     |   println(s"Mapping value $x to $newX...")
     |   newX
     | }.foreach {x =>
     |   println(s"Printing value $x")
     | }
Mapping value 1 to 2...
Printing value 2
Mapping value 2 to 4...
Printing value 4
Mapping value 3 to 6...
Printing value 6

请注意,对于Stream,我们只在完成前一个元素的所有操作后处理下一个map操作? Map操作仍会返回新流(Stream(2, 4, 6)),但仅在需要时才会使用值。

Stream在任何特定情况下的效果是否优于List,取决于您尝试做的事情。如果性能是您的主要目标,我建议您对代码进行基准测试(使用ScalaMeter等工具)来确定哪种类型效果最佳。

BTW,由于StreamList都是Seq的子类,因此通常的做法是编写需要序列来使用Seq的代码。这样,您可以提供List Stream 任何其他Seq子类,而无需更改代码,而无需将列表,流等转换为序列。例如:

def doSomethingWithSeq[T](seq: Seq[T]) = {
  //
}

// This works!
val list = List(1, 2, 3)
doSomethingWithSeq(list)

// This works too!
val stream = Stream(4, 5, 6)
doSomethingWithSeq(stream)

<强>已更新

List操作的StreamgroupBy的效果非常相似。根据它的使用方式,Stream可能需要的内存少于List,但可能需要一些额外的CPU时间。如果收集性能肯定是问题,那么对两种类型的收集(见上文)进行基准测试并精确测量以确定两者之间的权衡。我无法为你做出决心。您引用的缓慢可能是数据库和应用程序之间的数据传输,而与集合类型无关。

有关 Scala 集合效果的一般信息,请参阅Collections: Performance Charateristics

更新2

另请注意,任何类型的 Scala 序列通常一次由一个线程按顺序处理(因此名称)。 ListStream都不适合并行处理其元素。如果您需要并行处理集合,则需要 parallel 集合类型(scala.collection.parallel中的一个集合)。 scala.collection.parallel.ParSeq应该比groupByList更快地处理Stream,但前提是您有多个核心/超线程可用。但是,ParSeq操作不保证保留分组依据元素的顺序。