哪些Scala功能性能较差

时间:2013-04-25 08:38:27

标签: performance scala jvm

我最近在游荡:因为Scala在JVM上运行,而后者针对某些类型的操作进行了优化,是否存在在JVM上实现效率非常低的功能,因此应该不鼓励使用?你能解释为什么它们效率低下吗?

第一个候选者是函数式编程特性 - 我知道,函数是带有apply方法的特殊类,与函数只是代码块的语言相比,这显然会产生额外的开销。

1 个答案:

答案 0 :(得分:8)

性能调优是一个深刻而复杂的问题,但有三件事情会立即浮现在脑海中。

Scala集合对表现力有好处,但对性能不利。

考虑:

(1 to 20).map(x => x*x).sum

val a = new Array[Int](20)
var i = 0
while (i < 20) { a(i) = i+1; i += 1 }  // (1 to 20)
i = 0
while (i < 20) { a(i) = a(i)*a(i); i += 1 }   // map(x => x*x)
var s = 0
i = 0
while (i < 20) { s += a(i); i += 1 }  // sum
s

第一个是非常紧凑。第二个快了16倍。整数数学真的很快;拳击和拆箱不是。通用集合代码是通用的,并且依赖于装箱。

Function2仅专注于Int,Long和Double参数。

对基元的任何其他操作都需要装箱。小心!

假设您想要一个可以切换功能的功能 - 也许您想要大写字母或不大写字母。你试试:

def doOdd(a: Array[Char], f: (Char, Boolean) => Char) = {
  var i = 0
  while (i<a.length) { a(i) = f(a(i), (i&1)==1); i += 1 }
  a
}

然后你

val text = "The quick brown fox jumps over the lazy dog".toArray
val f = (c: Char, b: Boolean) => if (b) c.toUpper else c.toLower

scala> println( doOdd(text, f).mkString )
tHe qUiCk bRoWn fOx jUmPs oVeR ThE LaZy dOg

好的,太棒了!除非我们

trait Func_CB_C { def apply(c: Char, b: Boolean): Char }
val g = new Func_CB_C {
  def apply(c: Char, b: Boolean) = if (b) c.toUpper else c.toLower
}
def doOdd2(a: Array[Char], f: Func_CB_C) = {
  var i = 0
  while (i<a.length) { a(i) = f(a(i), (i&1)==1); i += 1 }
  a
}

代替?突然间它快了3倍。但是如果它是(Int, Int) => Int,(或者Int / Long / Double参数和Unit / Boolean / Int / Long / Float / Double返回值的任何其他排列),那么滚动自己是不必要的 - 它是专门的并且最大限度地工作速度。

仅仅因为你可以轻松并行化并不意味着它是一个好主意。

Scala的并行集合将尝试并行运行您的代码。这取决于你确保有足够的工作,以便并行运行是一件明智的事情。设置线程和收集结果有很多开销。举个例子,

val v = (1 to 1000).to[Vector]
v.map(x => x*(x+1))

val u = (1 to 1000).to[Vector].par
u.map(x => x*(x+1))

第二张地图更快,对,因为它是平行的?

几乎!由于开销(在我的机器上;结果可能大不相同),它慢了10倍

摘要

除了代码中性能最关键的部分之外,这些只是您通常不必担心的一些问题。有更多的东西,最终你会遇到,但正如我在评论中提到的,它需要一本书来涵盖它们中的一小部分。请注意,任何语言都存在很多性能问题,优化通常很棘手。在重要的地方省力!