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

128 阅读2分钟

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

高质量编程

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

  • 各种边界条件是否考虑完备
  • 异常处理,保证稳定性
  • 易读易维护 通用原则
  • 简单性
    • 容易理解 逻辑清晰
  • 可读性
  • 生产力
    • 提高团队整体工作效率

编码规范

  • 代码格式
    • gofmt自动格式化代码
  • 注释
    • 代码作用,解释公共常量、公共变量、函数、结构体等
    • 代码如何做
    • 代码实现原因
    • 代码什么情况下会出错
  • 命名规范
    • 参数名表示实际功能比较好
    • 变量
      • 缩略词全大写
      • 变量距离其被使用的地方越远,需要携带悦动上下文信息
    • 函数
      • 不需要携带包名信息,实际调用时会 包名.函数名
      • 只由小写字母组成,无下划线
      • 单数
      • 不使用常见变量名
      • 简短并包含上下文信息
  • 控制流程
    • 避免分支上的嵌套
    • 减少循环、嵌套,优先处理错误或特殊情况
  • 错误和异常处理
    • fmt.Errorf中使用%关键字来将一个错误关联至错误链中
    • 错误链 errors.ls()
    • 获取特定种类的错误 errors.As()
    • 不建议在业务代码中使用panic,在程序启动阶段可能发生不可逆转的错误时 可在init 或 main中用panic
    • recover 只能在当前goroutine生效,在defer中用,可在recover后在log中记录当前的调用栈 多个defer是后进先出,defer语句会在函数返回前调用

性能优化建议

如何评估

go test -bench=. -benchmem

优化建议

  • slice切片,尽可能在使用make()初始化切片时提供容量信息(预分配内存)
    data := make([] int, 0, size)
    
    • 数组容量不够时,要先扩容才插入新数据
    • 避免大内存未释放,使用copy代替re-slice
  • map预分配内存
    • 无预分配,添加元素触发扩容
    • 减少内存拷贝和rehash的消耗
  • 字符串处理
    • 代替+, strings.Builder 处理拼接字符串(和java类似)
  • 使用空结构体节省内存,仅作占位符
    • 实现Set可用map代替,且只用到key, value可用空结构体
    m := make(map[int]struct{})
    m[i] = struct{}{}
    
  • atomic包 原子操作
    • 比直接用sync.Mutexlock加锁要高效,锁属于系统调用

性能调优实战

简介

  • 调优原则
    • 要依靠数据不是猜测

    • 要定位最大瓶颈而不是细枝末节

    • 不要过早优化

    • 不要过度优化

性能分析工具 pprof

调优案例

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