使用官方自带benchmark进行基准性能测试
第一个是函数名-核数 第二个是执行次数 第三个是一次执行时间
第四个是一次执行的多大的内存 第五个是一次执行申请几次内存
slice用的时候在make()初始化切片时提供容量信息
data:=make([]int,0)
data:=make([]int,0,size)//good pre
slice:Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go 中提供了一种灵活,功能强悍的内置类型切片(“动态数组”),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。
在已有切片基础上创建切片,不会创建新的底层数组。
所以如上图所示:最好是copy而不是re-slice 差距能好多倍内存
2.map的预分配和slice是类似的 还是预分配就是好的
3.字符串处理:使用string builder更好
4.使用atomic包可以显著提升时间性能(相比于加锁 锁是os弄的 成本高,atomic是硬件实现的。)
预期:避免常见的陷阱
普通的应用不要一味追求性能
越高级的优化手段越容易出现问题
优化的前提是正确可靠、简洁清晰
性能调优原则:
依靠数据而不是猜测(benchmark)
定位最大的优化空间 最大的瓶颈 而不是细枝末节
不要过早优化 没必要 出现问题再说
不要过度优化 因为还得迭代 逻辑可能不兼容
性能分析工具pprof
go get -d github.com/wolfogre/go-pprof-practice
cd $GOPATH/src/github.com/wolfogre/go-pprof-practice
go build
./go-pprof-practice
运行后注意查看一下资源是否吃紧,机器是否还能扛得住,坚持一分钟,如果确认没问题,咱们再进行下一步。
控制台里应该会不停的打印日志,都是一些“猫狗虎鼠在不停地吃喝拉撒”。没有意义,不用细看。
1.排查CPU占用
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=10
输入top之后
解释:
flat是当前函数本身的执行耗时
sum%是上面每一行的flat%总和
cum是当前函数本身加上其调用函数的总耗时
cum%是cum占CPU总时间的比例
能发现tiger.eat是最大的占用
输入list Eat
发现消耗了5.59s的是这一行代码 循环了好多好多好多次
2.排查RAM占用
对于内存RAM的排查 类似上面的 也可以通过任务管理器来看出来异常占用。
3.排查协程
由于 golang 自带内存回收,所以一般不会发生内存泄露。但凡事都有例外,在 golang 中,协程本身是可能泄露的,或者叫协程失控,进而导致内存泄露。
我们在浏览器里可以看到,此时程序的协程数已经多达 116条:
go tool pprof http://localhost:6060/debug/pprof/goroutine
同样是 top、list、web 大法:发现问题在:
func (w *Wolf) Drink() {log.Println(w.Name(), "drink")for i := 0; i < 10; i++ {go func() {time.Sleep(30 * time.Second)//这里很大问题}()}
}
可以看到,Drink 函数每次会释放 10 个协程出去,每个协程会睡眠 30 秒再退出,而 Drink 函数又会被反复调用,这才导致大量协程泄露,试想一下,如果释放出的协程会永久阻塞,那么泄露的协程数便会持续增加,内存的占用也会持续增加,那迟早是会被操作系统杀死的。
总结:pprof可以通过网页和可视化终端来分析性能问题
可以采样CPU 堆内存 协程 锁 阻塞 线程创建 等等问题