2014-01-27 122 views
4

我喜欢Scala的理解力以及它们与任何带有地图和flatMap的monadic类型的整合方式。但是,我也想做简单的整数循环,而不会造成主要的速度损失。为什么Scala没有以下两个逻辑上相同的循环运行时具有相似的运行时性能,甚至编译成相似的字节码?为什么Scala for循环比逻辑上的循环慢?

// This is slow... 
for (i <- 0 until n) println(s"for loop with $i") 

// This runs much faster. It runs roughly at the same speed as Java code doing an identical while or for loop. 
var i = 0; 
while (i < n) { 
    println(s"while loop with $i") 
    i += 1 
} 
+0

确认一下...你*的*与编译'-optimize',不是吗? –

+0

@KevinWright:我很难找到'-optimize'选项实际所做的任何描述。你有没有指向任何描述其效果的指针? –

+0

@RandallSchulz它随着版本的不同而不同,但您可以在这里得到一个公平的想法:http://magarciaepfl.github.io/scala/ –

回答

4

为什么他们不同的主要(但不仅仅是)拳击。

在代码:

for (i <- 0 until n) println(s"for loop with $i") 

你传递一个匿名函数println(s"for loop with $i")入修真​​。这相当于:

(0 until n) foreach (i => 
    println(s"for loop with $i") 
} 

这个功能是在字节码,这意味着i不能是原始int抹去,它必须被装箱为Integer代替。 Java没有Fixnum引用来避免这种代价,就像例如Smalltalk确实(尤其令人沮丧的是,给定了多少旧的Smalltalk!)

使用-optimize可以帮助在某些情况下,尤其是在scalac的主干构建中。

您还可以使用scalaxy/loops加快速度:)

+0

使用-optimize选项时要小心,因为某些库遇到问题。我相信阿卡就是其中之一。 –

+0

这是信息丰富的,但它仍然只是一个借口。 Scala编译器可以清楚地解决这个问题。对整数进行装箱整理对于编译器实现来说可能更简单和更清晰,但是没有理由字节码不能使用未装箱的Java原始整数。 – user2684301

+1

@ user2684301这将是一个跨项目优化,目前稳定的编译器不会这样做。 'Range.foreach'需要一个* Generic *函数,因此优化需要将'foreach'的实现从标准库复制到使用的代码中,然后进行专门化 - 这会为二进制兼容性带来各种乐趣。 –