一、简介
- 性能调优的前提是满足正确可靠、简洁清晰等质量因素
- 性能优化的目标是使系统能够更快地完成任务、更高效地利用资源,并提供更好的用户体验
- 性能优化是综合评估,有时候时间效率和空间效率可能对立
- 针对Go语言特性,介绍Go相关的性能优化建议
二、Benchmark
基准测试(benchmark)是 go testing 库提供的,用来度量程序性能,算法优劣的利器。
指定一个时间(默认是1秒),看测试对象在达到时间上限时,最多能被执行多少次和在此期间测试对象内存分配情况。
基本规则
- 准测试的代码文件必须以_test.go结尾
- 基准测试的函数必须以Benchmark开头,必须是可导出的
- 基准测试函数必须接受一个指向Benchmark类型的指针作为唯一参数
- b.ResetTimer是重置计时器,这样可以避免for循环之前的初始化代码的干扰
- 最后的for循环很重要,被测试的代码要放到循环里
- b.N是基准测试框架提供的,表示循环的次数,因为需要反复调用测试的代码,才可以评估性能
常用命令
go test -bench=. -benchmem
- 使用
-bench=.标记,它接受一个表达式作为参数,匹配基准测试的函数,.表示运行所有基准测试。 - 使用
-benchmem提供每次操作分配内存的次数,以及每次操作分配的字节数。 - 使用
-run=none匹配单元测试方法,这里使用none是因为没有这个名字的单元测试方法,等效于过滤掉单元测试的输出。 - 使用
-benchtime=3s指定测试的时间,例如3秒,测试时间默认是1秒。 - 使用
-count=3用来设置 benchmark 的轮数。例如,进行3轮benchmark。
三、slice预分配内存
在Go语言中,可以使用内置的make函数来创建一个具有预分配内存的切片。预分配内存可以提高切片的性能,减少动态内存分配的次数。
make函数的语法是:make([]T, length, capacity),其中T是切片的元素类型,length是切片的初始长度,capacity是切片的预分配容量。
内存占用与释放
在Go语言中,切片的内存占用和释放是由运行时系统自动管理的。当创建一个切片时,运行时系统会自动分配一块内存来存储切片的元素。当切片不再被使用时,运行时系统会自动释放该内存。
当切片的长度超过了其容量时,运行时系统会自动为切片分配更多的内存,并将原始数据复制到新的内存中。这个过程被称为切片的扩容。切片的扩容是自动进行的,开发者无需手动管理。
当切片不再被引用时,也就是没有任何变量指向该切片时,运行时系统会自动回收切片所占用的内存。这是通过垃圾回收机制来实现的。
虽然Go语言的内存管理是自动的,但是为了避免不必要的内存占用,我们可以通过将不再使用的切片设置为nil来显式释放内存。将切片设置为nil会使其不再被引用,从而触发垃圾回收机制来回收切片所占用的内存。
以下是一个示例:
package main
import "fmt"
func main() {
s := make([]int, 0, 5)
// 使用切片...
// 释放切片的内存
s = nil
// 手动触发垃圾回收
// runtime.GC()
// 使用其他变量...
}
四、map预分配内存
在Go语言中,可以使用make函数来创建一个预分配了指定容量的map。make函数的第二个参数是map的容量,表示可以存储的键值对数量。
通过预分配容量,我们可以看到map在每次添加键值对时,容量会逐渐增加。这样,就可以减少map的动态内存分配次数,提高性能。
需要注意的是,预分配的容量并不会限制map的长度。map可以根据需要动态扩展,直到达到运行时系统限制的最大长度。