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

64 阅读2分钟

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

主要内容:

  • 如何编写更简洁清晰的代码
  • 常用 Go 语言程序优化手段
  • 熟悉 Go 程序性能分析工具
  • 了解工程中性能优化的原则和流程

01 高质量编程

代码格式:gofmt,自带;goimport

注释

编码规范:

  • 简洁胜于冗长

  • 缩略词全大写,但当其位于变量开头且不需要导出时,使用全小写

    • 例如使用 ServeHTTP 而不是 Servehttp
    • 使用 XMLHTTPRequest 或者 xmlHTTPRequest
  • 变量距离其被使用的地方越远,则需要携带越多的上下文信息

  • 全局变量在其名字中需要更多的上下文信息,使得在不同地方可以轻易辦认出其含义

  • package

    • 只由小写字母组成。不包含大写字母和下划线等字符
    • 简短并包含一定的上下文信息。例如 schema、 task等
    • 不要与标准库同名。例如不要使用 sync 或者 strings
    • 不使用常用变量名作为包名。例如使用 bufio 而不是 buf
    • 使用单数而不是复数。例如使用 encoding 而不是 encodings
    • 谨慎地使用缩写。例如使用 fmt 在不破坏上下文的情况下比 format 更加简短
  • 控制流程避免嵌套;优先处理错误情况/特殊情况,尽早返回或继续循环

     if err := doSomething(); err != nil {
         return err
     }
     return nil
    
  • 简单错误

    • 简单的错误指的是仅出现一次的错误,且在其他地方不需要捕获该错误
    • 优先使用 errors.New 来创建匿名变量来直接表示简单错误
    • 如果有格式化的需求,使用 fmt.Errorf
  • 错误的 Wrap 和 Unwrap 使用%w关键字关联错误至错误链

     return fmt.Errorf("xxx: %w", err)
    

    错误判定用 errors.is ,不同于使用 == ,使用该方法可以判定错误链上的所有错误是否含有特定的错误

     if errors.Is(err, fs.ErrNotExist)
    

    使用 errors.As 在错误链上获取特定种类的错误

性能优化:

BenchMark 基准性能测试工具

  • silice 预分配内存: 尽可能在使用 make() 初始化切片时提供容量信息
  • 陷阱—大内存未释放:已有切片基础上新建小切片,底层数组得不到释放。用copy代替re-slice
  • map 预分配内存:提前分配好空间可以减少内存拷贝和 Rehash 的消耗
  • 使用 strings.Builder 拼接字符串
  • 使用空结构体节省内存:例如用map实现Set,只需要key,可以将map的value类型设置为struct,因为即使是bool也要1个字节空间
  • 使用 atomic 包进行线程保护操作

02 性能调优实战

性能分析工具 pprof

采样-Sample

  • CPU
  • 堆内存-Heap
  • 协程-Goroutine

介绍了采样过程和原理

案例

  • 业务服务优化
  • 基础库优化
  • 编译器&运行时优化