Go高质量编程与性能调优|青训营笔记
这是我参与「第五届青训营」伴学笔记创作活动的第3天。
一、本堂课重点内容
- 高质量编程的定义、方法及原则
- 编码规范
- 性能优化的相关建议
- 性能调优
二、详细知识点介绍
1. 高质量编程
1.1 简介
- 高质量
- 编写的代码能够达到正确可靠、简洁清晰
- 边界条件是否考虑完备
- 异常情况处理
- 易读易维护
- 编程原则
- 简单性
- 消除多余的复杂性,简单清晰的逻辑
- 不理解的代码无法修复改进
- 可读性
- 人刻度
- 编写可维护代码第一步需要确保代码可读性
- 生产力
- 整体工作效率重要
- 简单性
1.2 编码规范
- 代码格式
- 使用gofmt自动格式化代码
- 注释
- 解释代码作用/如何实现/实现的原因/什么情况会出错
- 公共符号需要注释
- 包中声明的每个公共的符号:变量、常量、函数及结构都需要注释
- 任何不明显不简短的公共功能需要注释
- 无论长度、复杂度如何,库中任何函数必须注释
- 命名规范
- variable
- 简介胜于冗长
- 缩略词全大写,位于变量开头且不需导出时使用全小写
- 变量距离被使用的地方越远,越需要更多的context信息
- 全局变量名需要更多信息
- function
- 函数名不携带包的context,因为包和函数名成对出现
- 函数名尽量简短
- 名foo返回类型Foo可以省略类型信息
- 名foo返回类型T可以在函数名中加入类型信息
- package
- 只有小写字母组成
- 简短包含一定的context
- 不要与标准库同名
- 不使用常用变量名作为包名
- 使用单数
- 谨慎使用缩写
- variable
- 控制流程
- 避免嵌套,保持正常流程清晰
- 尽量保持正常代码路径为最小缩进,优先处理特殊/错误情况,尽早返回/继续循环减少嵌套
- 错误/异常处理
- 简单错误:仅出现一次,优先使用errors.New创建匿名变量来直接表示简单错误
- 有格式化需求可使用fmt.Errorf
- 错误判定:可以使用errors.Is,可以判断错误链上是否含有特定错误
- 错误链上获取特定种类错误,使用errors.As
- panic不使用recover会造成程序崩溃
- 在程序启动阶段发生不可逆转错误时可以在init或main中使用panic
- recover只能在defer的函数中使用
- 嵌套不生效
- 只在当前的goroutine生效
- defer语句后进先出
1.3 性能优化建议
- 简介
- 性能优化前提是满足正确可靠、简洁清晰
- 性能优化是综合评估,时间、空间效率可能对立
- Benchmark
- 评估代码的性能表现:go test -bench=. -benchmem
- 结果包含测试函数名、执行次数、每次执行花费的时间、每次执行申请的内存大小、每次执行申请几次内存
- 评估代码的性能表现: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高
- slice尽可能在make初始化时提供容量信息
2. 性能调优实战
2.1 性能调优简介
- 依靠数据而不是猜测
- 定位最大瓶颈
- 不要过早、过度优化
2.2 性能分析工具pprof
- 用于可视化和分析性能分析数据的工具
- pprof工具
- 分析profile
- 网页
- 可视化终端
- 展示 view
- top
- 调用图
- 火焰图
- peek
- 源码
- 反汇编
- 工具 tool
- runtime/pprof
- net/http/pprof
- 采样 sample
- cpu
- 堆内存 heap
- 协程 goroutine
- 锁 mutex
- 阻塞
- 线程创建
- 分析profile
三、实践案例
3.1 pprof性能排查实战
- CPU 可以看到占用的cpu内容
- topN 查看资源占用最多的函数
- flat:当前函数本身的执行耗时
- flat%:占cpu总时间的比例
- sum%:上面每一行的flat%总和
- cum:当前函数本身加上调用函数的总耗时
- cum%:cum占CPU总时间的比例
- list 根据指定正则表达式排查
- web 调用关系可视化
- topN 查看资源占用最多的函数
- Heap 堆内存
- 使用http端 go tool pprof -hhtp=:8080 "http://localhost:6060/debug/pprof/heap"
- 排查内存高占用,进行调整
- 查找alloc_space
- Goroutine 协程泄露
- 从上到下表示调用顺序
- 每一块代表一个函数,越长代表CPU占用越长
- 动态火焰图,支持点击块进行分析
- Mutex 锁
- block 阻塞
四、课后个人总结
本节课主要讲解了go编码的要点,以及性能相关的内容。课程的重点在于性能相关调试和编码注意,因为在实战中编程的性能是十分重要的。本节课介绍了go中常用的性能排查工具pprof,需要在实战中加以使用和理解。