GolangNote

Golang笔记

提高go运行性能小技巧

Permalink3

有几个 tips 对提高 go 性能有帮助,分享一下

Reflection 是昂贵的

Reflection 来获取变量类型很方便,但会有性能消耗

代码行数的增加并不一定减少性能

比如下面功能的函数:

Go: append
1
2
3
func add(items []string, item string) []string{
   return append(items,item)
}

代码很简洁、易懂,但性能不好,较好的方式:

Go: append优化
1
2
3
4
5
6
7
8
9
func add(items []string, item string) []string{
   n := len(items)
   output := make([]string, n+1)
   for index, val := range items {
      output[index] = val
   }
   output[n] = item
   return output
}

基准测试代码:

Go: append基准测试
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package loc

import (
	"os"
	"testing"
)

const maxElements = 1000

var elements = make([]int, maxElements)

func TestMain(m *testing.M) {
	for i := 0; i < maxElements; i++ {
		elements[i] = i
	}
	os.Exit(m.Run())
}

func Add(items []int, item int) []int {
	return append(items, item)
}

func Add2(items []int, item int) []int {
	n := len(items)
	output := make([]int, n+1)
	output[n] = item
	copy(items[0:n], output)
	return output
}

func BenchmarkAdd(b *testing.B) {
	b.ReportAllocs()
	var result []int
	for i := 0; i < b.N; i++ {
		b.StartTimer()
		result = Add(elements, 10)
	}
	if len(result) != maxElements+1 {
		b.Fatalf("Invalid number of elements, expected %d but retrieved %d", maxElements+1, len(result))
	}
}

func BenchmarkAdd2(b *testing.B) {
	b.ReportAllocs()
	var result []int
	for i := 0; i < b.N; i++ {
		b.StartTimer()
		result = Add2(elements, 10)
	}
	if len(result) != maxElements+1 {
		b.Fatalf("Invalid number of elements, expected %d but retrieved %d", maxElements+1, len(result))
	}
}

// go test -bench=. -benchmem -memprofile memprofile.out -cpuprofile profile.out

当往 1000 个元素的数组添加一个元素时,第二种的性能是第一种的两倍。

使用内联函数

Testing

对象、变量尽可能长时间保留在内存中

Benchmark tests (基准测试)

本文网址: https://golangnote.com/topic/248.html 转摘请注明来源

Related articles

Golang Range 的性能提升Tip

Go 语言里使用 range 可以方便遍历数组(array)、切片(slice)、字典(map)和信道(chan)。这里主要关注他们的性能。...

Comments

There are 3 Comments to "提高go运行性能小技巧"

1 smallwhite says:
回复

个人认为这种情况预先加cap会比较靠谱。

Go: 预先加 cap
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

import (
	"os"
	"testing"
)

const maxElements = 1000
const cap = 2000

var elements = make([]int, maxElements, cap)

func TestMain(m *testing.M) {
	for i := 0; i < maxElements; i++ {
		elements[i] = i
	}
	os.Exit(m.Run())
}

func Add(items []int, item int) []int {
	return append(items, item)
}

func Add2(items []int, item int) []int {
	n := len(items)
	output := make([]int, n+1)
	output[n] = item
	copy(items[0:n], output)
	return output
}

func BenchmarkAdd(b *testing.B) {
	b.ReportAllocs()
	var result []int
	for i := 0; i < b.N; i++ {
		b.StartTimer()
		result = Add(elements, 10)
	}
	if len(result) != maxElements+1 {
		b.Fatalf("Invalid number of elements, expected %d but retrieved %d", maxElements+1, len(result))
	}
}

func BenchmarkAdd2(b *testing.B) {
	b.ReportAllocs()
	var result []int
	for i := 0; i < b.N; i++ {
		b.StartTimer()
		result = Add2(elements, 10)
	}
	if len(result) != maxElements+1 {
		b.Fatalf("Invalid number of elements, expected %d but retrieved %d", maxElements+1, len(result))
	}
}

2 GolangNote says:
回复

@smallwhite #1 预分配好,前提是预知长度。

3 golang小白 says:
回复

copy(items[0:n], output) 是不是应该换成 copy(output[:n], items)

Go: copy
1
2
copy(items[0:n], output)
return output

这样返回的 output 只有一个值吧

Write a Comment to "提高go运行性能小技巧"

Submit Comment Login
Based on Golang + fastHTTP + sdb | go1.22.3 Processed in 0ms