性能优化对于用户来说是重中之重。用户对于我们开发的项目没有一个良好的体验那这个项目就不算成功。所以在学习玩go的性能调优工具pprof之后,感受到了其在于性能观测方面的强大功能。以下对pprof工具的使用做我自己的小总结。我们基于一个性能漏洞比较多的项目进行pprof工具的学习,该项目会不断的在创造新的数据加入变量中导致内存占用较多,还在一些函数上加锁并调用sleep()占用cpu资源,在这种情况下性能的漏洞比较容易观察到。
通过浏览器观察基本指标
在程序运行起来之后可以通过浏览器进入localhost:/debug/pprof/来观测性能指标。
可以看到内存分配和对内存以及goroutine的数量并不少。我们可以通过浏览器来观察性能调优前和调优后的指标变化来对比调优的性能。
CPU
查看CPU占用资源来定位占用CPU资源多的代码位置。通过终端命令go tool pprof "http://localhost:6060/debug/pprof/profile?seconds=10"进入到pprof工具,再通过top命令来查看CPU资源
可以看到cpu资源的一些指标:
- flat:当前函数本身执行的时间
- flat%:执行函数本身占CPU总时间的比例
- sum%:上面的每一行的flat%总和
- cum:当前函数本身和其调用函数执行的总时间
- cum%:执行函数本身和其调用函数占CPU总时间的比例
熟悉这些指标后可以看到,红框的tiger.Eat这个函数本身执行的耗时占CPU最多,其调用函数执行的耗时也占CPU最多。所以基本可以定位该函数占用太多的CPU资源,需要进行优化。
通过list Eat命令可以定位到tiger.Eat这个函数占用CPU最多的代码:
定位到具体代码我们的目标就很明确了,要在这个for循环上做改动来改善其占用CPU资源的情况。
堆内存
堆内存也是一个重要的优化方向。在终端输入命令go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/heap",pprof会在浏览器打开视图来观察堆内存情况。
通过视图可以看到,堆内存占用较多的代码块在mouse.pee()和mouse.steal()这两个函数里面。这时我们可以像CPU一样通过list + 函数名来定位占用堆内存较多的具体代码。
go tool pprof "http://localhost:6060/debug/pprof/heap"
list Pee
list Steal
原来它们在不断往buffer里面加数据从而导致占用太多的堆内存,我们可以简单的注释掉来观察性能优化的效果:
可以看到堆内存占用已经减少了很多。
Goroutine
goroutine的泄露也会导致内存的泄露,所以也是一个重要的性能优化方向。步骤和之前的也类似也感觉到使用pprof工具的强大。终端通过命令go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/heap"来打开goroutine视图来观察。
可以看到wolf.drink()开启了不少的goroutine,每个goroutine都是在sleep状态没什么意义所以可以进行优化。
接下来也切换我们打开的pprof goroutine视图到source视图来定位开启goroutine较多的代码在哪里从而实现准确的优化。
Mutex锁
寻找程序中耗时较多的锁也是性能优化的一个方向,终端通过命令go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/mutex"来打开mutex视图来观察。
再通过终端pprof命令list Howl来定位包含锁的具体代码位置
Block阻塞
受到阻塞的代码块也是我们优化的目标之一,因为阻塞就会一直占用资源。寻找程序中耗时较多的锁也是性能优化的一个方向,终端通过命令go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/block"来打开block视图来观察。
可以看到wolf和cat的两个函数受到阻塞,需要进行优化
通过
list Pee 和list Howl来定位受到阻塞的具体代码
总结
通过一轮性能调优的实践,对pprof工具了解加深了不少,其使用方法以及观测指标也是熟悉了不少。对性能优化的步骤以及方向也有不少的了解。继续进行实践对不同的项目,巩固性能调优的只是以及pprof工具的使用。