高质量编程与性能调优实战 | 青训营笔记

55 阅读3分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的的第3篇笔记。

编码规范

代码格式

gofmt:Go语言官方提供的格式化代码工具

goimports:Go语言官方提供的依赖包管理工具

注释

  1. 注释应该解释代码的作用
  2. 注释应该解释代码如何做的
  3. 注释应该解释代码实现的原因
  4. 注释应该解释代码什么情况会出错
  5. 公共符号始终要注释

命名规范

variable

  1. 缩略词全大写,但其位于变量开头且不需要导出时全小写
  2. 变量距离被使用的地方越远,越需要携带更多的上下文信息
  3. 变量使用有特定含义的名词

函数名

  1. 函数名不携带包名的上下文信息,尽量简短
  2. foo包某个函数返回类型Foo时可省略类型信息,返回类型不是Foo时可以在函数名中加入类型信息
  3. 导出的函数大写字母开头,非导出的小写字母开头

package:(必须)只包含小写字母,简短,包含一定的上下文信息,不要与标准库同名,(尽量)不用常用变量名,使用单数,谨慎缩写。

控制流程

  1. 处理逻辑尽量走直线,避免嵌套
  2. 尽量保持正常代码路径为最小缩进,也就是说错误处理流程嵌套进控制流程中

错误和异常处理

简单错误:指仅出现一次的错误,优先使用errors.New创建匿名变量表示,如果有格式化需求使用fmt.Errorf,用%w将一个错误关联到错误链中。

错误判定erros.Is判断错误链上所有错误是否含有特定的错误,errors.As在错误链上获取特定种类的错误。

panic:不可逆转的错误可以使用panic,不建议业务代码使用panic。

recover:recover只能在当前goroutine中被defer的函数中使用,嵌套无法生效,defer的顺序是后进先出。

性能优化

性能优化建议

  1. Benchmark:go test -bench=. -benchmem
  2. slice:尽量make初始化时提供容量信息,copy替代re-slice
  3. map:尽量预分配内存
  4. 使用strings.Builder代替bytes.Buffer+
  5. 使用空结构体做占位符
  6. 变量保护使用atomic代替加锁

性能调优原则

  1. 依靠数据不要猜测
  2. 定位最大瓶颈
  3. 不要过早优化
  4. 不要过度优化

性能分析工具 pprof

测试用的项目:github.com/wolfogre/go…

go run main.c运行测试程序,浏览器输入http://localhost:6060/debug/pprof/进入pprof监控页面:

image.png

  1. CPU

首先用top命令查看:

image.png

CPU占用率达到了77.7%。

终端使用命令go tool pprof "http://localhost:6060/debug/pprof/profile?seconds=10",采集10秒的数据:

image.png

top命令查看CPU占用情况:

image.png

看到老虎在吃的函数占用最多,用list定位代码:

image.png

哦嚯,有个空循环,注释掉这段代码。

  1. 内存

终端使用命令go tool pprof "http://localhost:6060/debug/pprof/heap",查看内存:

image.png

输入top

image.png

老鼠偷掉了绝大多数内存,用list命令:

image.png

定位到代码,注释掉。

  1. 协程

终端使用命令go tool pprof "http://localhost:6060/debug/pprof/goroutine",一样使用toplist定位:

image.png

剩下的锁和阻塞一样的排查方法,同时如果觉得命令行不够直观,也可以调用UI界面:

go tool pprof -http=:8888 "http://localhost:6060/debug/pprof/goroutine"

image.png

根据提示安装graphviz

sudo pacman -S graphviz

再次运行pprof:

image.png

或者也可以用UI打开pprof保存的文件:

go tool pprof -http localhost:8888 ~/pprof/pprof.main.alloc_objects.alloc_space.inuse_objects.inuse_space.001.pb.gz