这是我参与「第五届青训营 」笔记创作活动的第3天
Day3
高质量编程及编码规范
高质量代码:正确可靠,简洁清晰。正确性、完备性、易维护
gofmt:Go语言官方工具,能自动格式化go语言代码为官方统一风格
goimports:也是Go语言官方工具,等于gofmt加上依赖包管理,能自动增删依赖的包引用,并按字母序排列。
注释Tips:
- 解释代码作用
- 解释代码如何做
- 解释代码实现原因
- 解释代码出错情况(限制条件)
代码是最好的注释,注释应该提供代码为表达出来的上下文信息
命名规范:
- 简介胜于冗长
- 缩略词全大写,但当其位于变量开头且不需要导出时全小写。
- 变量距离其被使用的地方越远,则需要携带更多上下文信息
package:只有小写字母组成,简短并包含一定上下文信息,不与标准库同名
以下规则尽量满足:
- 不使用常用变量名作为包名。例如bufio而不是buf
- 使用单数而不是复数。例如使用encoding而不是encodings
- 谨慎使用缩写。
控制流程:避免嵌套,保持正常流程清晰
错误与异常处理:优先使用errors.New来创建匿名变量来直接表示简单错误,若有格式化要求,使用fmt.Errorf
error的三个API:errors.Is、errors.As、errors.Unwrap
fmt.Errorf能使用%w关键字来将一个错误关联至错误链中。
errors.Is能够进行错误判定:是否包含指定类型错误
errors.As能讲特定错误内容取出
- error尽可能提供简明的上下文信息,方便定位问题。
- panic用于真正异常的情况。
- recover生效范围,再当前goroutine的被defer函数中生效。
性能优化
go test自带benchmark工具,能实现程序基准性能测试
主要注意的点在于预分配,对于slice,其实包含一个指向底层数组的指针,如果能够预分配,能够减少溢出时内存分配的时间,对于map来说,底层是平衡树结构,直接预分配能够一次构建成功,时间复杂度较小,若后续逐渐添加,会在内存分配和rebalancing上面有损耗。
特殊场景:在已有切片上创建切片,不会创建新的底层数组
- 原切片较大,在原切片基础上新建小切片
- 原底层数组在内存中有引用,得不到释放。
可用copy代替re-slice
字符串拼接不建议使用直接加,byte.Buffer更好。字符串是不可变类型,占用内存大小固定,每次使用+会重新分配内存,strings.Builder,bytes.Buffer底层是[]byte数组。如果增加预分配代码性能会更好。
性能优化分析工具
- 要依靠数据不是猜测
- 要定位最大瓶颈而不是细枝末节
- 不要过早优化
- 不要过度优化
go tool pprof "http://localhost:6060/debug/pprof/profile?seconds=10"
主要调优工具pprof,可通过上述语句进行采样并将数据存入文件,采样时间为10s。
通过top命令查看性能瓶颈,之后可通过list Eat列出具体执行函数的性能消耗
go tool pprof -http=:8000 "http://localhost:6060/debug/pprof/heap"
能够在浏览器中得到一个性能分析的可视化视图。
goroutine泄露也会导致内存泄漏
go tool pprof -http=:8000 "http://localhost:6060/debug/pprof/goroutine"