Algorithm Scala与Java性能
我遇到了Scala和Java性能之间的一个非常奇怪的差异。我在Java中实现了一个反转计数例程,然后将它逐行移植到Scala,因为所有惯用的Scala版本(使用Algorithm Scala与Java性能,algorithm,scala,sorting,Algorithm,Scala,Sorting,我遇到了Scala和Java性能之间的一个非常奇怪的差异。我在Java中实现了一个反转计数例程,然后将它逐行移植到Scala,因为所有惯用的Scala版本(使用List或Stream)要么非常慢,要么由于堆栈溢出/内存不足错误而崩溃。但是这个版本也很慢,而Java版本需要22毫秒来处理100000个整数的数组,Scala版本需要3秒钟。以下是Scala版本的相关代码: def mergeAndCountInversions(xs: Array[Int], aux: Array[Int], l
List
或Stream
)要么非常慢,要么由于堆栈溢出/内存不足错误而崩溃。但是这个版本也很慢,而Java版本需要22毫秒来处理100000个整数的数组,Scala版本需要3秒钟。以下是Scala版本的相关代码:
def mergeAndCountInversions(xs: Array[Int], aux: Array[Int], left: Int, right: Int) = {
xs.copyToArray(aux)
val m = left + (right - left) / 2
var i = left
var j = m + 1
var inv: Long = 0
for (k <- left to right) {
if (i > m) {
xs(k) = aux(j)
j += 1
} else if (j > right) {
xs(k) = aux(i)
i += 1
} else if (aux(j) < aux(i)) {
xs(k) = aux(j)
j += 1
inv += (m - i) + 1
} else {
xs(k) = aux(i)
i += 1
}
}
inv
}
def mergeAndCountInversions(xs:Array[Int],aux:Array[Int],left:Int,right:Int)={
X.copyToArray(辅助)
val m=左+(右-左)/2
变量i=左
var j=m+1
var inv:Long=0
用于(k m){
xs(k)=辅助(j)
j+=1
}否则,如果(j>正确){
xs(k)=辅助(i)
i+=1
}如果(辅助(j)<辅助(i)){
xs(k)=辅助(j)
j+=1
库存+=(m-i)+1
}否则{
xs(k)=辅助(i)
i+=1
}
}
投资部
}
关于如何提高这套动作的表现有什么想法吗
UPD:Scala版本性能差完全是我的错。第一条语句不必要地将整个数组复制到辅助数组。当改变为只复制所需的部分时,性能与java应该是一样的。
很可能是因为理解。它被剥去了糖衣
Range(left, right).foreach { k =>
// code...
}
为了使其与Java解决方案具有可比性,必须用while循环替换它
var k = left
while (k <= right) {
// code...
k += 1
}
var k=left
虽然(阿纳尔席)java(虽然我还没有足够的Scala WIZ来写一个答案,但是考虑到Scala中的数组索引在数组对象上调用<代码>应用程序/Cuff>方法-与使用方括号的数组访问语法时,在引擎盖下执行的指针算术不完全相同。首先,用以测量性能。预热后使用ce。我猜在内联后您将获得相同的性能。您也可以在编译时使用以下命令来强制内联:for(k@senia)我已经用使用的基准例程更新了这个问题。我发现,将scala的理解重建为尾部递归算法通常具有性能优势(如果你能做到的话)。编译器似乎在优化这些方面做得更好。啊,synapse,我刚刚在CodeReview上查看了你最初的Scala实现;)我想,你还没有完全理解尾部递归/优化。我已经给出了一个例子。是的,我认为这可能是原因,但性能与相同,而我不理解的是为什么Scala编译器没有找到优化范围的方法(…).foreach
构造成与Java for循环生成的相同的底层字节码…@ErikAllik for在scala中比通常的Java循环构造做了更多的工作为了优化最简单的情况,我用for和while测试了它,速度快得多。@drexin这真的很奇怪。你的环境是什么?我在Mac OS X上使用Scala 2.10.2和JDK 1.6。