Vas*_*nov 5 performance closures go
例如,github.com/yhat/scrape建议使用这样的闭包:
func someFunc() {
...
matcher := func(n *html.Node) bool {
return n.DataAtom == atom.Body
}
body, ok := scrape.Find(root, matcher)
...
}
Run Code Online (Sandbox Code Playgroud)
由于matcher实际上并没有捕获任何局部变量,因此这可以等效地写为:
func someFunc() {
...
body, ok := scrape.Find(root, matcher)
...
}
func matcher(n *html.Node) bool {
return n.DataAtom == atom.Body
}
Run Code Online (Sandbox Code Playgroud)
第一种形式看起来更好,因为 matcher 函数非常特定于代码中的那个地方。但是它在运行时的性能是否更差(假设someFunc可能经常被调用)?
我想创建一个闭包肯定会有一些开销,但是这种闭包可以被编译器优化成一个常规函数吗?
(显然语言规范不需要这个;我对 gc 实际做什么感兴趣。)
好像没什么区别。我们可以检入生成的机器码。
这是一个玩具程序:
package main
import "fmt"
func topLevelFunction(x int) int {
return x + 4
}
func useFunction(fn func(int) int) {
fmt.Println(fn(10))
}
func invoke() {
innerFunction := func(x int) int {
return x + 8
}
useFunction(topLevelFunction)
useFunction(innerFunction)
}
func main() {
invoke()
}
Run Code Online (Sandbox Code Playgroud)
这是它的反汇编:
$ go version
go version go1.8.5 linux/amd64
$ go tool objdump -s 'main\.(invoke|topLevel)' bin/toy
TEXT main.topLevelFunction(SB) /home/vasiliy/cur/work/learn-go/src/my/toy/toy.go
toy.go:6 0x47b7a0 488b442408 MOVQ 0x8(SP), AX
toy.go:6 0x47b7a5 4883c004 ADDQ $0x4, AX
toy.go:6 0x47b7a9 4889442410 MOVQ AX, 0x10(SP)
toy.go:6 0x47b7ae c3 RET
TEXT main.invoke(SB) /home/vasiliy/cur/work/learn-go/src/my/toy/toy.go
toy.go:13 0x47b870 64488b0c25f8ffffff FS MOVQ FS:0xfffffff8, CX
toy.go:13 0x47b879 483b6110 CMPQ 0x10(CX), SP
toy.go:13 0x47b87d 7638 JBE 0x47b8b7
toy.go:13 0x47b87f 4883ec10 SUBQ $0x10, SP
toy.go:13 0x47b883 48896c2408 MOVQ BP, 0x8(SP)
toy.go:13 0x47b888 488d6c2408 LEAQ 0x8(SP), BP
toy.go:17 0x47b88d 488d052cfb0200 LEAQ 0x2fb2c(IP), AX
toy.go:17 0x47b894 48890424 MOVQ AX, 0(SP)
toy.go:17 0x47b898 e813ffffff CALL main.useFunction(SB)
toy.go:14 0x47b89d 488d0514fb0200 LEAQ 0x2fb14(IP), AX
toy.go:18 0x47b8a4 48890424 MOVQ AX, 0(SP)
toy.go:18 0x47b8a8 e803ffffff CALL main.useFunction(SB)
toy.go:19 0x47b8ad 488b6c2408 MOVQ 0x8(SP), BP
toy.go:19 0x47b8b2 4883c410 ADDQ $0x10, SP
toy.go:19 0x47b8b6 c3 RET
toy.go:13 0x47b8b7 e874f7fcff CALL runtime.morestack_noctxt(SB)
toy.go:13 0x47b8bc ebb2 JMP main.invoke(SB)
TEXT main.invoke.func1(SB) /home/vasiliy/cur/work/learn-go/src/my/toy/toy.go
toy.go:15 0x47b8f0 488b442408 MOVQ 0x8(SP), AX
toy.go:15 0x47b8f5 4883c008 ADDQ $0x8, AX
toy.go:15 0x47b8f9 4889442410 MOVQ AX, 0x10(SP)
toy.go:15 0x47b8fe c3 RET
Run Code Online (Sandbox Code Playgroud)
正如我们所见,至少在这个简单的例子中,topLevelFunction和innerFunction( invoke.func1) 以及它们传递到 的方式没有结构差异useFunction,被转换为机器代码。
(将其与innerFunction捕获局部变量的情况进行比较是有益的;此外,innerFunction与通过全局变量而不是函数参数传递的情况进行比较是有益的——但这些留给读者作为练习。)
| 归档时间: |
|
| 查看次数: |
3210 次 |
| 最近记录: |