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

76 阅读5分钟

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

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

一、本堂课重点内容

  • 高质量编程的定义、方法及原则
  • 编码规范
  • 性能优化的相关建议
  • 性能调优

二、详细知识点介绍

1. 高质量编程

1.1 简介

  • 高质量
    • 编写的代码能够达到正确可靠、简洁清晰
    • 边界条件是否考虑完备
    • 异常情况处理
    • 易读易维护
  • 编程原则
    • 简单性
      • 消除多余的复杂性,简单清晰的逻辑
      • 不理解的代码无法修复改进
    • 可读性
      • 人刻度
      • 编写可维护代码第一步需要确保代码可读性
    • 生产力
      • 整体工作效率重要

1.2 编码规范

  • 代码格式
    • 使用gofmt自动格式化代码
  • 注释
    • 解释代码作用/如何实现/实现的原因/什么情况会出错
    • 公共符号需要注释
    • 包中声明的每个公共的符号:变量、常量、函数及结构都需要注释
    • 任何不明显不简短的公共功能需要注释
    • 无论长度、复杂度如何,库中任何函数必须注释
  • 命名规范
    • variable
      • 简介胜于冗长
      • 缩略词全大写,位于变量开头且不需导出时使用全小写
      • 变量距离被使用的地方越远,越需要更多的context信息
        • 全局变量名需要更多信息
    • function
      • 函数名不携带包的context,因为包和函数名成对出现
      • 函数名尽量简短
      • 名foo返回类型Foo可以省略类型信息
      • 名foo返回类型T可以在函数名中加入类型信息
    • package
      • 只有小写字母组成
      • 简短包含一定的context
      • 不要与标准库同名
      • 不使用常用变量名作为包名
      • 使用单数
      • 谨慎使用缩写
  • 控制流程
    • 避免嵌套,保持正常流程清晰
    • 尽量保持正常代码路径为最小缩进,优先处理特殊/错误情况,尽早返回/继续循环减少嵌套
  • 错误/异常处理
    • 简单错误:仅出现一次,优先使用errors.New创建匿名变量来直接表示简单错误
    • 有格式化需求可使用fmt.Errorf
    • 错误判定:可以使用errors.Is,可以判断错误链上是否含有特定错误
    • 错误链上获取特定种类错误,使用errors.As
    • panic不使用recover会造成程序崩溃
      • 在程序启动阶段发生不可逆转错误时可以在init或main中使用panic
      • recover只能在defer的函数中使用
        • 嵌套不生效
        • 只在当前的goroutine生效
        • defer语句后进先出

1.3 性能优化建议

  • 简介
    • 性能优化前提是满足正确可靠、简洁清晰
    • 性能优化是综合评估,时间、空间效率可能对立
  • Benchmark
    • 评估代码的性能表现:go test -bench=. -benchmem
      • 结果包含测试函数名、执行次数、每次执行花费的时间、每次执行申请的内存大小、每次执行申请几次内存
  • 性能优化建议
    • slice尽可能在make初始化时提供容量信息
      • 切片是数组片段的描述
      • 切片操作不复制切片指向的元素
      • 创建新切片会复用原切片的底层数组
      • 容易导致大内存未释放(利用copy代替reslice)
    • map预分配内存
      • 不断向map中添加元素会触发map扩容
      • 提前分配空间可以减少内存拷贝和rehash消耗
      • 根据实际需求提前预估需要的空间
    • 字符串处理
      • 使用strings.Builder代替+=拼接字符串
      • bytes.Buffer相近,但在转化字符串时需要重新申请一块空间;strings.Builder直接将底层[]byte转化为字符串类型返回
      • 预知字符串长度时可以使用pre体现规划大小
    • 空结构体
      • 空结构体可以节省内存,本身不占用任何内存
      • 实现Set可以用map代替
    • atomic包
      • 使用atomic包比mutex锁效果更好
      • atomic操作使用硬件实现,效率比Mutex高

2. 性能调优实战

2.1 性能调优简介

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

2.2 性能分析工具pprof

  • 用于可视化和分析性能分析数据的工具
  • pprof工具
    • 分析profile
      • 网页
      • 可视化终端
    • 展示 view
      • top
      • 调用图
      • 火焰图
      • peek
      • 源码
      • 反汇编
    • 工具 tool
      • runtime/pprof
      • net/http/pprof
    • 采样 sample
      • cpu
      • 堆内存 heap
      • 协程 goroutine
      • 锁 mutex
      • 阻塞
      • 线程创建

三、实践案例

3.1 pprof性能排查实战

  • CPU 可以看到占用的cpu内容
    • topN 查看资源占用最多的函数
      • flat:当前函数本身的执行耗时
      • flat%:占cpu总时间的比例
      • sum%:上面每一行的flat%总和
      • cum:当前函数本身加上调用函数的总耗时
      • cum%:cum占CPU总时间的比例
    • list 根据指定正则表达式排查
    • web 调用关系可视化
  • Heap 堆内存
  • Goroutine 协程泄露
    • 从上到下表示调用顺序
    • 每一块代表一个函数,越长代表CPU占用越长
    • 动态火焰图,支持点击块进行分析
  • Mutex 锁
  • block 阻塞

四、课后个人总结

本节课主要讲解了go编码的要点,以及性能相关的内容。课程的重点在于性能相关调试和编码注意,因为在实战中编程的性能是十分重要的。本节课介绍了go中常用的性能排查工具pprof,需要在实战中加以使用和理解。

五、引用