Golang中如何优化这个简单的斐波那契函数?

Golang中如何优化这个简单的斐波那契函数? 我编写了这个简单的函数,它迭代1000次,每次迭代计算1250次斐波那契数列,并将每个数字追加到切片中。我的目标是创建一个模拟CPU工作的函数。谢谢!

func fibonacci() []int {
	var result []int
	var start = 1000
	for {
		var num = 1250
		var n1, n2, temp int = 0, 1, 0

		for {
			temp = n2
			n2 = n1 + n2
			n1 = temp

			result = append(result, n2)
			if num <= 1 {
				break
			}
			num--
		}
		if start <= 1 {
			break
		}
		start--
	}
	return result
}

更多关于Golang中如何优化这个简单的斐波那契函数?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

8 回复

太棒了,仅此一项就带来了显著的改进。

更多关于Golang中如何优化这个简单的斐波那契函数?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


如何改进?是太快了还是太慢了?

@NobbZ 感谢您的详细解释,这完全说得通。关于Go语言还有很多需要学习的地方 🙂
@NobbZ 在优化之前,我的测试结果是每秒340个请求,现在达到了每秒1,245个请求。我很好奇为什么这个优化能带来如此显著的提升?

我正在学习Go语言,想知道这段代码能否优化得更快?有没有更好的编写方式能让性能更出色?

func main() {
    fmt.Println("hello world")
}

既然你已经知道需要1250个元素,可以预先分配切片。

result := make([]int, 0, 1250)

或者甚至

result := make([]int, 1250)

…
for {
  …
  result[1250 - num] = n2
  …
}

编辑

我刚意识到,你正在用相同的数字重复追加1000次…所以你需要相应地调整容量/大小和索引计算。

内存分配代价高昂,复制大块内存更是如此。

由于切片本质上是带有"长度"和"容量"的胖指针,其工作原理如下:

从零长度的切片开始。首次追加元素时,会分配容量为10的空间(具体数值可能有所不同,但大致相当),长度变为1,元素被插入其中。 长度持续增加直到插入操作将超出容量,此时会重新分配双倍容量(20)的内存块,复制原有内容,并将新元素添加到末尾。 随后容量依次倍增为40、80、160、320、640、1280、2560、5120、10240、20480、40960、81920、163840、327680、655360、1310720。

这意味着需要经历18次扩容,总共复制约1310710个元素的数据。按每个int类型占4字节计算,相当于5242840字节或约5.1MiB。

通过预分配可以避免所有这些复制操作。

以下是针对您提供的斐波那契函数的优化建议。原函数通过嵌套循环模拟CPU工作,但存在一些性能瓶颈,如重复的切片追加和变量初始化。我将展示优化后的代码,并解释关键改进点。

优化后的代码

func fibonacciOptimized() []int {
    const outerIterations = 1000
    const innerIterations = 1250
    totalElements := outerIterations * innerIterations
    result := make([]int, 0, totalElements)

    for i := 0; i < outerIterations; i++ {
        n1, n2 := 0, 1
        for j := 0; j < innerIterations; j++ {
            n1, n2 = n2, n1+n2
            result = append(result, n2)
        }
    }
    return result
}

优化点解释

  1. 预分配切片容量:使用 make([]int, 0, totalElements) 预分配切片容量,避免 append 操作时的多次内存重新分配。原函数在每次 append 时可能触发底层数组扩容,增加开销。

  2. 简化循环结构:将无限循环 for {} 改为固定次数的 for 循环,使用常量 outerIterationsinnerIterations 提高可读性。原代码使用 startnum 变量递减,容易出错。

  3. 优化变量赋值:使用并行赋值 n1, n2 = n2, n1+n2 替换临时变量 temp,减少变量操作和内存访问。

  4. 移除冗余初始化:将变量 n1n2 的初始化移至外层循环内,避免在每次内层循环重复初始化(原代码中 n1, n2, temp 在内层循环外初始化,但实际应在每次外层循环重置)。

性能对比

  • 原函数:在每次 append 时可能频繁扩容切片,且循环控制复杂。
  • 优化后:预分配内存减少分配次数,循环结构清晰,变量操作更高效。

运行优化后的函数会生成相同的结果(包含 1,250,000 个斐波那契数),但执行速度更快,尤其在大迭代次数下。您可以通过基准测试验证改进,例如使用 testing.B 在Go中测试性能。

如果目标是最大化CPU负载,可以考虑进一步优化,如使用循环展开或并行计算(例如goroutine),但当前优化已显著提升单线程性能。

回到顶部