Golang中函数变量比普通函数执行更快吗?

Golang中函数变量比普通函数执行更快吗? 我在做一道 LeetCode 题目时,发现这段代码:

func floodFill(image [][]int, sr int, sc int, color int) [][]int {
    original :=image[sr][sc] 
    if original == color {
        return image
    }

    fill(image,  sr, sc, color, original)

    return image
}

func fill(image [][]int, sr int, sc int, color int, original int) {
    image[sr][sc] = color

    if sr > 0 && image[sr-1][sc] == original {
        fill(image,  sr-1, sc, color, original)
    }

    if sc > 0 && image[sr][sc-1] == original {
        fill(image,   sr, sc-1, color, original)
    }

    if sc < len(image[0]) - 1 && image[sr][sc+1] == original {
        fill(image,  sr, sc+1, color, original)
    }

    if sr < len(image) - 1 && image[sr+1][sc] == original {
        fill(image,  sr+1, sc, color, original)
    }
}

实际上比另一段代码(3毫秒)要慢(10毫秒):

func floodFill(image [][]int, sr int, sc int, color int) [][]int {
    original :=image[sr][sc] 
    if original == color {
        return image
    }

    var fill func( sr int, sc int ) 
    fill = func(  sr int, sc int ) {
        image[sr][sc] = color

        if sr > 0 && image[sr-1][sc] == original {
            fill(  sr-1, sc )
        }

        if sc > 0 && image[sr][sc-1] == original {
            fill(   sr, sc-1 )
        }

        if sc < len(image[0]) - 1 && image[sr][sc+1] == original {
            fill(  sr, sc+1 )
        }

        if sr < len(image) - 1 && image[sr+1][sc] == original {
            fill(  sr+1, sc )
        }
    }

    fill(  sr, sc )

    return image
}

这是他们平台的一个副作用(运行第一个版本的实例稍微快一些),还是这暗示了函数变量比函数更快?


更多关于Golang中函数变量比普通函数执行更快吗?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

闭包与函数并无区别。使你的代码更快的原因是闭包参数数量的减少;实际上,你使用的是 image[][] 的本地实例,而不是在每次调用时传递它(第一种情况 + color + original)。

这是按值调用编程语言中 lambda 表达式的优势之一(如果使用得当)。

另外……不要将 LeetCode 的运行时间视为金科玉律,如果你多次运行程序,实际上总会得到不同的(有时差异很大)结果。

更多关于Golang中函数变量比普通函数执行更快吗?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go语言中,函数变量(闭包)与普通函数的性能差异通常很小,但确实存在。你观察到的现象主要源于以下几个因素:

  1. 闭包访问外部变量:第二个版本中,闭包fill通过闭包引用访问imageoriginal变量,避免了参数传递的开销。
  2. 参数数量减少:闭包版本只有srsc两个参数,而普通函数版本有5个参数。参数传递在栈上操作,参数越多开销越大。
  3. 编译器优化:闭包可能被编译器更积极地内联优化。

下面是性能对比的示例代码:

package main

import (
    "testing"
)

// 普通函数版本
func fillFunc(image [][]int, sr, sc, color, original int) {
    // 实现同你的第一个版本
}

// 闭包版本
func fillClosure(image [][]int, sr, sc, color, original int) {
    var fill func(sr, sc int)
    fill = func(sr, sc int) {
        // 实现同你的第二个版本
    }
    fill(sr, sc)
}

func BenchmarkFunc(b *testing.B) {
    image := make([][]int, 100)
    for i := range image {
        image[i] = make([]int, 100)
    }
    for i := 0; i < b.N; i++ {
        fillFunc(image, 50, 50, 2, 1)
    }
}

func BenchmarkClosure(b *testing.B) {
    image := make([][]int, 100)
    for i := range image {
        image[i] = make([]int, 100)
    }
    for i := 0; i < b.N; i++ {
        fillClosure(image, 50, 50, 2, 1)
    }
}

运行基准测试:

go test -bench=. -benchmem

典型结果可能显示闭包版本稍快(约5-10%),差异主要来自:

  • 闭包减少了参数复制
  • 闭包直接引用外部变量,减少了栈操作
  • 但闭包有额外的内存分配(函数对象)

在递归深度较大时,参数减少带来的性能提升更明显。对于LeetCode这类平台,3ms和10ms的差异可能在测量误差范围内,但闭包版本确实有潜在的性能优势。

回到顶部