我有一个场景,其中以对象流的形式获取数据库数据。在将其转换为对象序列时,需要花费一定的时间。我正在寻找更快的替代方法。
我有一个场景,其中以对象流的形式获取数据库数据。在将其转换为对象序列时,需要花费一定的时间。我正在寻找更快的替代方法。
$ 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.collection.immutable.Stream
) 也是 Seq
的子类,但它是 lazy (或 non-strict),这意味着只有在需要时才会获取流的下一个值。它通常被称为 lazy list。Stream
和 List
之间的区别,让我们重新做一遍那个例子: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)对代码进行基准测试,以确定哪种类型效果最佳。Stream
和List
都是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)
更新
在进行groupBy
操作时,List
和Stream
的性能非常相似。根据使用方式不同,Stream
可能需要比List
更少的内存,但可能需要一些额外的CPU时间。如果集合性能确实是问题,那么对两种类型的集合进行基准测试(见上文),并精确地测量以确定两者之间的权衡。我无法为您做出这种决定。可能你所说的缓慢是由于数据库和应用程序之间数据传输导致的,与集合类型无关。
有关Scala集合性能的一般信息,请参阅集合:性能特性。
更新2
还要注意,任何类型的Scala序列通常都会被单个线程按顺序(因此名称)处理,一个接一个。 List
和Stream
都不适合并行处理它们的元素。如果需要并行处理集合,则需要一种parallel集合类型(scala.collection.parallel
中的一个集合)。 scala.collection.parallel.ParSeq
应该比List
或Stream
更快地处理groupBy
,但前提是您有多个核心/超线程可用。但是,ParSeq
操作不能保证保留分组元素的顺序。