高质量编程和性能调优课程笔记 | 青训营笔记

76 阅读5分钟

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

高质量编程是项目开发的基础,优质的编程能为阅读代码、调试代码、小组合作以及项目交付和维护等提供支持,具体到现实,也能为青训的抖音项目的开发提供帮助。

1 高质量编程

1.1 简介

  • 边界条件完备
  • 异常情况保证稳定性
  • 易读易维护

编程原则:简单性、可读性、提高生产力

1.2 编码规范

编码规范包括注释规范、命名规范、控制流程规范、错误和异常处理规范等。

代码格式化工具

  • gofmt 实际使用中,可以用Goland中的快捷键control+alt+L来格式化。
  • goimports

注释

注释应该解释代码的作用、如何做的、实现的原因、什么情况下会出错。

例如函数前说明一下函数的功能、输入和返回值,函数中的一些复杂/关键部分提供额外注释,一些不容易看懂的代码或者容易出错的代码提供一些解释说明,避免无用或者重复啰嗦的注释。

命名规范

原则

  • 简介胜于冗长
  • 缩略词全大写,不需要导出的时候开头可以全小写
  • 全局变量最好多带一些信息,局部变量可以更简洁
  • 函数名不携带包名的上下文信息并且尽量简短
  • 包名只由小写字母组成,简短并包含一定信息,且不与标准库同名,尽量不使用常用变量名

实际规范

  1. 包名 小写且有意义的单词
  2. 文件名 小写单词,用下划线隔开
  3. 结构体名 驼峰法,对外暴露时首字母大写,否则小写
  4. 接口er结尾,首字母根据访问控制大写或者小写
  5. 变量名 与结构体类似,驼峰法并且首字母根据访问控制大写或者小写,若为bool类型则为is等开头
  6. 常量名 全大写
  7. 错误 必须捕获处理而不能用_舍弃

控制流程

  • 去掉多余else
  • 保持正常代码路径为最小缩进,减少嵌套,尽早返回异常情况
  • 故障处理一般放在复杂的控制语句中

错误和异常处理

  • 简单错误使用errors.New或者fmt.Errorf处理
  • 使用错误的Wrap和Unwarp提供跟踪链
  • errors.Is可以判定错误的类型
  • 获取并判断错误链上特定种类的错误用error.As
  • panic不建议在业务代码中使用,不包含recover会导致程序崩溃
  • recover只能在被defer的函数中使用,只在当前goroutine生效,注意defer是后进先出

1.3 性能优化建议

Benchmark

go test -bench=. -benchmem

Slice

预分配内存-尽可能在使用make()初始化切片时提供容量信息。

size := 10
array := make([]int, 0, size)

在大切片的基础上新建小切片会导致原数组在内存中引用而无法释放内存,可使用copy替代reslice。

Map

预分配内存-根据需求提前预估大小。不断向map中添加元素的操作会触发map的扩容,提前分配好空间可以减少内存拷贝和Rehash的消耗。

字符串处理

使用strings.Builder来拼接字符串以提高性能减少内存消耗,原因是string字符串使用+拼接每次都会重新分配内存,而strings.Builder底层采用byte[]来存储,不需要每次拼接都重分配内存。

空结构体

struct{}不占据任何内存空间,可作为占位符使用,可以用map将struct{}作为值实现Set。

Atomic

使用atomic包比mutex性能好

atomic.AddInt32(&i,1)

锁的实现是通过操作系统来实现,属于系统调用。atomic操作是通过硬件实现,效率比锁高。 sync.Mutex应该用来保护一段逻辑,不仅仅用于保护一个变量,当只保护一个变量时,应该使用atomic来代替mutex

2 性能调优实战

2.1 调优原则

  • 依靠数据而非猜测
  • 定位最大瓶颈
  • 不要过早和过度优化

2.2 性能分析工具 pprof

image-20220516212009-j9vi16p.png 实战:github.com/wolfogre/go…

Cpu

命令行输入go tool pprof "http://localhost:6060/debug/pprof/profile?seconds=10",进入pprof分析

topN-查看占用资源最多的函数

参数含义
flat当前函数本身的执行耗时
flat%flat 占CPU 总时间的比例
sum%上面每一行的flat%总和
cum指当前函数本身加上其调用函数的总耗时
cum%cum 占 CPU总时间的比例

flat==cum时,函数中没有调用其他函数;flat==0时,函数中只有其他函数的调用。

list-根据指定正则表达式查找代码行

web-调用关系可视化

Heap

命令行输入go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/heap",进入pprof分析

top视图 与上面的top命令类似

source视图 与上面的list命令类似

Goroutine

命令行输入go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/goroutine",进入pprof分析

top视图和source视图同上

Mutex

命令行输入go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/mutex",进入pprof分析

top视图和source视图同上

pprof采样过程和原理

CPU采样函数调用和占用时间,100次/秒。

Heap通过内存分配器在堆上分配和释放内存记录,每分配512KB记录一次。

2.3 性能调优案例

保证正确性,定位主要瓶颈。

业务服务优化

结合整体的调用链路,进行具体分析,适用范围不够广。

基础库优化

适用范围广,优化提升不大但由于覆盖范围广所以节省资源巨大。

Go语言优化

由于所有程序都使用go语言,所有对go语言的优化通用性强,对所有go语言开发的项目都适用。