这是我参与「第三届青训营 -后端场」笔记创作活动的的第2篇笔记。
我们可以通过Go语言开发各种各样的项目,但是完成程序逻辑本身的同时,如何让程序运行得更加高效,也是应该被考虑的。
性能调优应该遵循以下原则:
要依赖数据而非猜测
要定位最大瓶颈而非细枝末节
不要过早优化
不要过度优化
Golang中自带的pprof工具可以让我们可视化分析性能数据。将pprof的路由注册到http server的指定端口上,即可通过localhost的指定端口访问性能数据。
使用命令
go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/指定指标"
(6060为pprof所运行的端口)
即可在localhost的8080端口可视化程序运行性能数据。
此外,在SDK层面也可以做更通用的优化。
Golang中内存分配模型是多级的,在GMP模型中的每一个P(Process)都拥有属于自己的线程缓存(Thread Cache),第二级是公用的中心缓存(Central Cache),第三级则是页堆(Page Heap)。
当需要向对象分配内存时,如果是小对象,则会在线程缓存上分配,不能满足需求,则在中心缓存上解决。遇到32KB以上的对象时,则直接在页堆上分配。
在现实中的程序中,小对象的分配往往占大多数,而Golang原本的内存分配,至少需要g->m->p的调用路径,这将消耗一定时间。而可以通过在每个Goroutine上绑定一定大小缓存用来分配小对象的内存,即可加快小对象分配的效率。
编译的优化也是一个有意义的方向。Golang本身追求编译效率,在编译时对代码的分析优化比较少(控制流分析、数据流分析、过程内分析、过程间分析等),同时内联策略比较保守。通过修改Golang编译时的行为,促进分析优化、内联等行为,则可通过牺牲一定的编译时间、运行镜像大小的代价换取更高的运行性能。