这是我参与「第五届青训营」伴学笔记创作活动的第4天
一、高质量编程
1.1 编程原则
- 简单性
- 可读性
- 生产力
1.2 编码规范
1.2.1 代码格式
使用gofmt自动格式化代码,goimports依赖包管理
1.2.2 注释
注释要:
- 解释代码作用
- 解释代码如何作用
- 解释实现原因
- 解释什么情况会出错
1.2.3 命名规范
变量:
- 简洁
- 缩写词全大写
- 变量使用距离远,要携带更多上下文信息
pacakge:
- 包名只由小写组成,不含大写字母和下划线
- 简短,包含上下文信息
- 不与标准库重名
函数:
- 不用携带包的上下文信息,因为它们往往成对出现
- 名为f的函数返回F类型,可以省略类型信息不导致歧义
1.2.4 控制流程
优先处理特殊情况,尽早return减少嵌套。
1.2.5 错误和异常处理
错误
简单错误: 简单错误是指仅出现一次的错误,在其它地方不用捕获该错误。优先使用errors.New()创建匿名变量直接表示错误,格式化要求用发fmt.Errorf。
复杂错误: 在fmt.Errorf中使用%w format关键字把错误关联至错误链
错误判定: error.Is()判断是否为特定错误,也可以判断错误链上是否有特定错误。errors.As()获取错误链上的特定错误。
异常
当程序中发生严重错误时,可能导致程序崩溃,使用panic抛出,一定要再在defer中调用recover
二、性能优化
2.1 benchmark
使用要求
- 基准测试的代码文件以_test.go结尾
- 基准测试的函数以Benchmark开头
- 接受一个指向Benchmark类型的指针作为唯一参数
- 不能有返回值
- 被测试的代码要放到循环里
- 执行命令:go test -bench=. -benchmen
参数分析
-8 cpu核数 执行次数 每次执行时间花费 每次执行申请多大内存 每次执行申请几次
2.2 优化建议
- slice预分配内存
- map预分配内存
- 复杂字符串拼接用strings.Builder
- atomic,如想在多线程中实现个计数器。atomic操作通过硬件实现,效率比锁高。对于非数值操作,可以用atomic.Value
三、性能调优实战
3.1 分析工具
example: wolfogre/go-pprof-practice: go pprof practice. (github.com)
web页面:go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/heap"
需要安装graphviz,bin目录添加到path,不起效果重启
3.2 基本使用
以采样十秒为基准来分析性能
命令:go tool pprof "http://localhost:6060/debug/pprof/profile?seconds=10"
cpu
首先查看cpu情况,可以发现Eat函数消耗cpu最多
参数解释:
- flat:当前函数本身的执行耗时
- flat%:flat占CPU总时间的比例
- sum%:上面每一行的flat%总和
- cum:指当前函数本身加上其调用函数的总耗时
- cum%:cum占CPU总时间的比例
思考: 什么情况flat=cum,float=0呢?
-
Flat =Cum,函数中没有调用其他函数
-
Flat=0,函数中只有其他函数的调用
已知Eat函数消耗cpu最多,于是进一步检查该函数,发现有一个巨大的循环
内存
查看内存情况,发现Mouse.Steal消耗了大量内存
还是通过list Steal来定位问题,发现buffer append了大量的内存