所以Scala应该和Java一样快.我正在重新审视我最初用Java解决的Scala中的一些Project Euler问题.具体问题5:"从1到20的所有数字均可被整除的最小正数是多少?"
这是我的Java解决方案,在我的机器上完成需要0.7秒:
public class P005_evenly_divisible implements Runnable{
final int t = 20;
public void run() {
int i = 10;
while(!isEvenlyDivisible(i, t)){
i += 2;
}
System.out.println(i);
}
boolean isEvenlyDivisible(int a, int b){
for (int i = 2; i <= b; i++) {
if (a % i != 0)
return false;
}
return true;
}
public static void main(String[] args) {
new P005_evenly_divisible().run();
}
}
Run Code Online (Sandbox Code Playgroud)
这是我对Scala的"直接翻译",需要103秒(147倍!)
object P005_JavaStyle {
val t:Int = 20;
def run {
var …Run Code Online (Sandbox Code Playgroud) 有人说Scala For comprehension实际上很慢.给出我的原因是由于Java的限制,对于理解(例如"reduce",下面使用)需要在每次迭代时生成一个临时对象,以便调用传入的函数.
这是真的?下面的测试似乎证实了这一点,但我不完全理解为什么会这样.
这可能对"lambdas"或匿名函数有意义,但对于非匿名函数则无效.
在我的测试中,我针对list.reduce运行了循环(参见下面的代码),发现它们的速度超过了两倍,即使每次迭代都调用了传递给reduce的完全相同的函数!
我发现这非常反直觉(曾经认为Scala库会被仔细创建为尽可能最佳).
在我放在一起的测试中,我运行了相同的循环(总结数字1到100万,无论溢出)五种不同的方式:
结果如下:测试:最小/最大/平均(毫秒)
1. 27/157/64.78
2. 27/192/65.77 <--- note the similarity between tests 1,2 and 4,5
3. 139/313/202.58
4. 63/342/150.18
5. 63/341/149.99
Run Code Online (Sandbox Code Playgroud)
可以看出,"for comprehension"版本的顺序为"for for new for each instance",暗示实际上可以为匿名和非匿名函数版本执行"new".
方法:下面的代码(删除测试调用)被编译成单个.jar文件,以确保所有版本都运行相同的库代码.每次迭代中的每个测试都在一个新的JVM中调用(即scala -cp ...用于每个测试),以便消除堆大小问题.
class t(val i: Int) {
def summit(j: Int) = j + i
}
object bar {
val biglist:List[Int] = (1 to 1000000).toList
def summit(i: Int, j:Int) = i+j
// Simple for loop
def forloop: Int = { …Run Code Online (Sandbox Code Playgroud)