以下Scala代码在1.5分钟内完成,而GO中的等效代码在2.5分钟内完成 最高纤维(40)都需要2秒。间隙出现在fib(50)中 我得到的印象是GO,原生,应该比Scala更快。
Scala
def fib(n:Int):Long = {
n match {
case 0 => 0
case 1 => 1
case _ => fib(n-1) + fib(n-2)
}
}
GO
func fib(n int) (ret int) {
if n > 1 {
return fib(n-1) + fib(n-2)
}
return n
}
Scala优化?
Golang限制?
由于“我的另一辆车是一名干部”,所以问题是“在这个特殊的微基准测试中,Scala如何比GO更快?”
忘记Fibonacci让我说我确实有一个需要递归的函数 Scala在递归情况下是否优越?
它可能是内部编译器实现,甚至是Scala特定的优化 如果你知道,请回答。
在12秒内进入循环运行15000000000
func fib(n int) (two int) {
one := 0
two = 1
for i := 1; i != n; i++ {
one, two = two, (one + two)
}
return
}
答案 0 :(得分:3)
对于Go,使用迭代而不是递归。递归可以用具有显式堆栈的迭代替换。它避免了函数调用和调用堆栈管理的开销。例如,使用迭代并将n
从50增加到1000几乎不需要时间:
package main
import "fmt"
func fib(n int) (f int64) {
if n < 0 {
n = 0
}
a, b := int64(0), int64(1)
for i := 0; i < n; i++ {
f = a
a, b = b, a+b
}
return
}
func main() {
n := 1000
fmt.Println(n, fib(n))
}
输出:
$ time .fib
1000 8261794739546030242
real 0m0.001s
user 0m0.000s
sys 0m0.000s
使用适当的算法。避免指数时间复杂性。当性能很重要时,不要使用递归来表示Fibonacci数。
参考:
Recursive Algorithms in Computer Science Courses: Fibonacci Numbers and Binomial Coefficients
我们观察到分支递归的计算效率低下 几乎所有的教科书都没有适当地涵盖这些功能 计算机科学课程的前三年课程。 Fibonacci数和二项式系数经常被用作 分支递归函数的例子。但是,它们呈指数增长 时间复杂性很少被宣称,并且从未完全证实 教科书。替代线性时间迭代解决方案很少 提及。我们给出了这些递归函数的非常简单的证明 具有指数时间复杂度。
递归是定义和算法的有效技术 只进行一次递归调用,但如果是非常低效的话 它会进行两次或多次递归调用。因此递归方法是 作为概念工具而不是作为概念工具通常更有用 高效的计算工具。本文提出的证据是 成功地教授(超过五年)到一年级学生 在渥太华大学。建议递归为 问题解决和定义工具将在第二部分中介绍 第一个计算机科学课程但是,递归编程应该 推迟到课程结束(或者更好的是在课程结束时) 迭代后的第二个计算机科学课程的开头 程序掌握得很好,堆栈操作也很好理解。
答案 1 :(得分:0)
Scala解决方案将使用堆栈,因为它不是尾递归(在递归调用之后添加),但它根本不应该创建任何垃圾。
对于这种代码模式,最常见的是你使用的热点编译器(可能是服务器)只是比Go编译器更好的编译器。
如果您真的很好奇,可以download a debug build of the JVM, and have it print out the assembly code。