Go-性能优化、优化分析、调优实战pprof| 豆包MarsCode AI 刷题

106 阅读3分钟

使用官方自带benchmark进行基准性能测试: 第一个是函数名-核数 第二个是执行次数 第三个是一次执行时间 第四个是一次执行的多大的内存 第五个是一次执行申请几次内存

图片.png 1.

slice用的时候在make()初始化切片时提供容量信息

data:=make([]int,0)
data:=make([]int,0,size)//good pre

slice:Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go 中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。 在已有切片基础上创建切片,不会创建新的底层数组。

图片.png 所以如上图所示:最好是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

图片.png 输入top之后

图片.png 解释: flat是当前函数本身的执行耗时 sum%是上面每一行的flat%总和 cum是当前函数本身加上其调用函数的总耗时 cum%是cum占CPU总时间的比例 能发现tiger.eat是最大的占用

输入list Eat 发现消耗了5.59s的是这一行代码 循环了好多好多好多次

图片.png 2.排查RAM占用 对于内存RAM的排查 类似上面的 也可以通过任务管理器来看出来异常占用。

3.排查协程 由于 golang 自带内存回收,所以一般不会发生内存泄露。但凡事都有例外,在 golang 中,协程本身是可能泄露的,或者叫协程失控,进而导致内存泄露。

我们在浏览器里可以看到,此时程序的协程数已经多达 116条:

图片.png

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 堆内存 协程 锁 阻塞 线程创建 等等问题