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

54 阅读3分钟

image.png

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

本文导航:

  • 高质量编程
  • 性能调优实战

高质量编程

定义:编写的代码能够达到正确可靠、简洁清晰的目标。

  • 各种边界条件是否考虑完备
  • 异常情况处理,稳定性保证
  • 易读易维护

编程原则:简单性,可读性,生产力

编码的规范:代码格式,注释,命名规范,控制流程,错误和异常处理

  • 代码格式:推荐使用gofmt自动格式化代码

  • 注释

    • 解释代码作用
    • 描述如何编写的
    • 实现的原因
    • 什么情况会出错
    • 公共符号始终要注释
  • 命名规范

    • 简洁胜于冗长
    • 缩略词全大写
    • 变量越远越要多的携带上下文信息
    • 函数名不携带包名的上下文信息
    • 函数名尽量简短
    • 包名只由小写字母组成,简短包含上下文信息,不与标准库同名
    • 推荐:不使用常用变量名作为包名,使用单数而不是复数,谨慎地使用缩写
  • 控制流程

    • 避免嵌套,保持正常流程清晰
    • 尽量保持代码路径为最小缩进
  • 错误和异常处理

    • 简单错误:仅出现一次的错误,优先使用errors.New创建匿名变量,有格式化需求,使用fmt.Errorf

      func main() { 
          //errors.New的使用
          err:= errors.New("Sample Error") 
          if err != nil { 
              fmt.Print(err) 
          } 
          //fmt.Errof的
          const name, dept = "GeeksforGeeks", "CS"
          err:= fmt.Errorf("%q is a %q Portal.", name, dept) 
          fmt.Println(err.Error()) 
      }
      
    • Error Wrapping:提供了可以一个error嵌套另一个error功能,好处就是我们可以根据嵌套的error序列,生成一个error错误跟踪链。

      e := errors.New("原始错误e")
      w := fmt.Errorf("Wrap了一个错误%w", e)//%w来生成一个可以Wrapping Error
      

      errors包添加了3个工具函数,他们分别是UnwrapIsAs

      • Unwrap函数:为了获得被嵌套的error
      func main() {
          e := errors.New("原始错误e")
          w := fmt.Errorf("Wrap了一个错误%w", e)
          fmt.Println(errors.Unwrap(w))//得到一次嵌套的一个错误
      }
      
      • Is函数:解决嵌套的error是否相等问题

        func Is(err, target error) bool
        
        1. 如果errtarget是同一个,那么返回true
        2. 如果err 是一个wrap error,target也包含在这个嵌套error链中的话,那么也返回true
      • As函数:把error转为另外一个error(在wrapping error加入之后)

        var perr *os.PathError
        if errors.As(err, &perr) {
            fmt.Println(perr.Path)
        }
        
    • Go中引入的Exception处理:defer, panic, recover

      • Go中可以抛出一个panic的异常,然后在defer中通过recover捕获这个异常,然后正常处理
      package main
      
      import "fmt"
      
      func main(){
          fmt.Println("c")
           defer func(){ // 必须要先声明defer,否则不能捕获到panic异常
              fmt.Println("d")
              if err:=recover();err!=nil{
                  fmt.Println(err) // 这里的err其实就是panic传入的内容,55
              }
              fmt.Println("e")
          }()
      
          f() //开始调用f
          fmt.Println("f") //这里开始下面代码不会再执行
      }
      
      func f(){
          fmt.Println("a")
          panic("异常信息")
          fmt.Println("b") //这里开始下面代码不会再执行
          fmt.Println("f")
      }
      
      
      输出结果:
      
      c
      a
      d
      异常信息
      e
      

性能优化建议-Benchmark

benchmark工具

go test -bench=. -benchmem

性能优化建议-Slice

  • slice预分配内存

  • 大内存未释放

go test -run=. -v

性能优化建议-Map

  • map预分配内存

性能优化建议-字符串处理

strings. Builder

使用+拼接性能最差,strings. Builder,bytes. Builder相近,strings. Buffer更快

性能优化建议-空结构体

  • 使用空结构体节省内存

性能优化建议-atomic包

atomic包:原子性

性能调优实战

性能调优原则:依靠数据,定位最大瓶颈而不是细枝末节,不要过早优化,不要过度优化

性能分析工具:pprof

可视化和分析性能分析数据 image.png CPUHeap堆内存goroutine协程mutex锁block阻塞

pprof-排查实战

pprof-采样过程和原理

性能调优案例-业务服务优化

流程:

  • 建立服务性能评估手段
  • 分析性能数据,定位性能瓶颈
  • 重点优化项改造
  • 优化效果验证

性能调优案例-基础库优化

  • AB实验SDK的优化

性能调优案例-Go语言优化

  • 编译器&运行时优化