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

24 阅读4分钟

t01fe78c18ff2779fe7.jpg

这是我参与「第五届青训营 」伴学笔记创作活动的第 3 天


一、高质量编程

什么是高质量——编写的代码能够达到正确可靠、简洁清晰的目标可称之为高质量代码

  • 高质量代码编程原则
    • 简单性:消除“多余的复杂”,方便理解修复改进
    • 可读性:确保代码可读
    • 生产力:团队整体工作效率非常重要

编码规范

  • 代码格式:推荐使用gofmt自动化格式代码,也有部分使用goimports
  • 注释:
    • 注释应该解释代码作用:适合注释公共符号,避免重复解释,尽量提供有效信息
    • 代码如何做的:适合注释实现过程,对一些复杂难读的实现逻辑进行说明
    • 代码实现原因:适合解释的外部因素,提供额外的上下文
    • 代码什么情况会出错:适合解释代码的限制条件
  • 命名规范:
    • 简洁
    • 缩略词全大写,如ServerHTTP
    • 变量距离其被使用的地方越远,则需携带更多的上下文信息
    • 函数名不携带包名信息
    • 包名只由小写字母组成,简洁并包含上下文信息,不使用常用变量,使用单数
  • 控制流程:
    • 避免嵌套,保持流程清晰
    • 优先处理错误/特殊情况,尽早返回或继续循环来减少嵌套
    • 尽量保持正常代码为最小缩进
  • 错误和异常处理
    • 简单错误
      • 出现一次的错误,其他地方无需捕获
      • 优先使用errors.New来创建匿名变量表示简单错误
      • 如果有格式化需求,使用fmt.Errorf
    • 错误的Warp和Unwarp
      • 一个error嵌套另一个error,从而生成error的跟踪链
      • 在fmt.Errorf中使用:%w关键字来将一个错误关联至错误链中
      • 判断错误链上是否有特定错误,使用errors.Is
      • 在错误链上获取特定种类的错误,使用errors.As,可以获取到text信息
    • panic
      • 程序异常被叫做panic,当panic被抛出异常后,如果我们没有在程序中添加任何保护措施的话,程序就会打印出panic的详细情况之后,终止运行
      • 不推荐在业务代码中使用panic,若问题可以被屏蔽或解决,建议使用error代替panic
    • recover
      • 使当前程序从运行时的panic状态中恢复并重新获得流程控制权,如果调用了内置函数recover,并且定义该defer语句的函数发生了panic异常,recover会使用程序从panic中恢复,并且返回panic value,导致panic异常的函数不会继续执行,但能正常返回。在未发生panic时调用recover,recover会返回nil。
      • recover只有在defer调用的函数中有效
      • 嵌套无法生效
      • 只在当前goroutine生效
      • defer语句是后进先出
      • 在log中记录当前的调用栈,debug.Stack()
defer func(){
    if e := recover(); e != nil{
        f = nil
        err = fmt.Errorf("gitfs panic: %v\n%s", e , debug.Stack() )
    }
}

性能优化

go提供了基准性能测试的benchmark工具 go test -bench

  • slice 预分配内存
    • 尽可能在使用make()初始化切片时提供容量信息
    • 在已有切片基础上切片,不会创建新的底层数组,可使用cppy代替re-slice
  • map预分配内存
  • 字符串处理
    • 使用strings.Bulider,比bytes.buffer快一些,Grow可以预分配内存
  • 空结构体
    • 空结构体struct{}实例不占用内存空间
    • 可用做占位符使用
    • 实现set,可以考虑用map空结构体
  • atomic包
    • 原子性

二、性能调优实战

原则:依赖于数据进行优化,不要过早和过度优化,定位最大瓶颈

性能分析工具——pprof

go tool "http://xxx?seconds=10" 采集服务的性能数据,seconds为采集时长

  • 命令
  • topN:查看占用资源最多的函数

image.png Flat==Cum:函数中未调用其他函数

Flat==0:函数中只有其他函数调用

  • list:根据指定的正则表达式查找代码行
  • web:调用关系可视化
  • heap:堆内存分析,在url后加上heap, go tool pprof -http=:8080 "http://xxx/heap"
  • goroutine:协程分析,在url后加上goroutine, go tool pprof -http=:8080 "http://xxx/goroutine"
  • mutex:锁分析,在url后加上mutex, go tool pprof -http=:8080 "http://xxx/mutex"
  • bolck:阻塞分析,在url后加上bolck, go tool pprof -http=:8080 "http://xxx/bolck"

切换不同采样说明

  • alloc_objects:程序累计申请的对象数
  • inuse_objects:程序当前持有的对象数
  • alloc_space:程序累计申请的内存大小
  • inuse_space:程序当前占用的内存大小

参考资料

github.com/wolfogre/go…