Contents

Go内联

  • 概念:在编译时,对于简短的函数,直接内嵌调用的代码,即直接展开代码,而不是将函数单独放进栈中
  • 目的:为了减少函数调用时的堆栈等开销

性能对比

  • 编写 inline_test.go ,在函数定义前一行添加 //go:noinline 可以禁止编译器内联
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package main

import (
	"testing"
	"time"
)

//go:noinline
func maxNoinline(a, b int) int {
	if a < b {
		return b
	}
	return a
}

func maxInline(a, b int) int {
	if a < b {
		return b
	}
	return a
}

func BenchmarkNoInline(b *testing.B) {
	x, y := 1, 2
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		maxNoinline(x, y)
	}
}

func BenchmarkInline(b *testing.B) {
	x, y := 1, 2
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		maxInline(x, y)
	}
}
  • 基准测试一下
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
➜  p14 go test -bench='Inline$' -v inline_test.go 
goos: linux
goarch: amd64
cpu: Intel(R) Core(TM) i5-6200U CPU @ 2.30GHz
BenchmarkNoInline
BenchmarkNoInline-4     642340173                1.618 ns/op
BenchmarkInline
BenchmarkInline-4       1000000000               0.4066 ns/op
PASS
ok      command-line-arguments  1.696s
  • 禁止编译器内联也可以在测试的时候带上 -gcflags=all=-l 或者 -gcflags=-l 参数
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
➜  p14 go test -gcflags=all=-l -bench='Inline$' -v inline_test.go 
goos: linux
goarch: amd64
cpu: Intel(R) Core(TM) i5-6200U CPU @ 2.30GHz
BenchmarkNoInline
BenchmarkNoInline-4     718661420                1.600 ns/op
BenchmarkInline
BenchmarkInline-4       727264352                1.616 ns/op
PASS
ok      command-line-arguments  2.679s

手动内联

  • 手动展开后的代码
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
func BenchmarkInline1(b *testing.B) {
	x, y := 1, 2
	a := 0
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		if x < y {
			a = y
		} else {
			a = x
		}
	}
	b.StopTimer()
	fmt.Println(a)
}
  • 添加以下代码
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

func BenchmarkNoInline1(b *testing.B) {
	x, y := 1, 2
	a := 0
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		a = maxNoinline(x, y)
	}
	b.StopTimer()
	fmt.Println(a)
}

func BenchmarkInline1(b *testing.B) {
	x, y := 1, 2
	a := 0
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		if x < y {
			a = y
		} else {
			a = x
		}
	}
	b.StopTimer()
	fmt.Println(a)
}
  • 测试校验
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
➜  p14 go test -bench='Inline' -v inline_test.go 
goos: linux
goarch: amd64
cpu: Intel(R) Core(TM) i5-6200U CPU @ 2.30GHz
BenchmarkNoInline
BenchmarkNoInline-4     694474184                1.660 ns/op
BenchmarkInline
BenchmarkInline-4       1000000000               0.4273 ns/op
BenchmarkNoInline1
# ……
BenchmarkNoInline1-4    521572680                2.040 ns/op
BenchmarkInline1
# ……
BenchmarkInline1-4      1000000000               0.4184 ns/op
PASS
ok      command-line-arguments  4.058s

本文参考

coffee