这是我参与「第五届青训营 」笔记创作活动的第3天
高质量编程
高质量编程简介
--编写的代码能够正确可靠,简洁清晰的目标
边界条件是否考虑完备? 异常情况处理,稳定性保证 易读易维护
编程原则
简单性,消除“多余的复杂性”,不理解的代码是无法修复改进的
可读性,代码是给被人看的,编写可维护代码的第一步是确保代码可读
生产力,团队整体工作效率非常重要
代码格式
对剑使用gofmt自动格式化代码
注释
注释公共符号
注释实现过程
提供额外上下文,解释代码的外部因素
结束代码的限制条件,什么时候回出错
代码规范
命名规范
缩略词全大写,如果是不用导出的函数,函数名开头要小写
变量距离被使用的地方越远,则需要携带越多的上下文信息
函数名不携带包名的上下文信息,因为包名和函数名总是成对出现,函数名尽量简短
当名为foo的函数返回T类型时,可以在函数名中加入类型信息
package:只用小写字母,不包含大写字母和下划线等字符,简短并包含一定的上下文信息,例如schema,task等 不要与标准库同名,也不使用常用变量名去给包命名
流程
避免分支上的嵌套
尽量保持正常代码路径为最小缩进
错误和异常处理
简单错误:只出现一次,且在其他地方不需要捕获该错误,优先使用errors.New创建匿名变量来直接表示简单错误
Wrap & Unwrap :
错误的wrap提供一个error嵌套另一个error的能力,从而生成了一个error的跟踪链
在fmt.error中使用%W关键字来将一个错误关联至错误链中
性能优化建议
怎么评估代码性能?
Benchmark
Go语言提供了支持基准性能测试的benchmark工具
go test -bench=.运行
Slice
Slice预分配内存
尽可能在使用mark()初始化切片提供容量信息
- 切片本质是一个数组片段的描述 包括数组指针,片段长度,片段容量
- 切片操作并不复制切片指向的元素
- 创建一个新的切片会复用原来切片的底层数组
陷阱:大内存未释放
在已有切片的基础上创建切片,不会创建新的底层数组
当原切片较大时,代码在原切基础上新建小切片,底层数组在内存中有引用,得不到释放
解决:用copy替代re-slice
空结构体
使用空结构体节省内存
空结构体实例不占用内存,可以在各种场景下当做占位符来用
atomic包
锁的实现时通过操作系统来实现,属于系统调用
atomic操作是通过硬件来实现,效率比锁搞
sync.Mutex应该用来保护一段逻辑,不仅仅用于保护一个变量
对于非数值操作,可以使用atomi.value,能承载一个interface{}
性能调优实战
性能调优原则
- 依靠数据而不是猜测
- 要定位最大瓶颈而不是细枝末节
- 不要过早优化
- 不要过度优化
性能调优简洁
性能分析工具pprof
希望知道应用在什么地方耗费了多少CPU,Memory
是用于可视化和分析性能分析数据的工具
排查实战
命令行分析
go tool pprof "[http://localhost:6060/debug/pprof/profile?seconds=10]"
CPU
命令:top查看占用资源最多的函数
什么情况下 Flat == Cum?函数中没有调用其他函数
什么时候Flat = 0,函数中只有其他函数的调用
list
web调用关系可视化,使用该命令进行调用关系可视化的时候,需要安装好graphviz并设置好环境变量,否则会出现"dot": executable file not found in %PATH%
调用关系图,火焰图
go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/cpu"
排查堆内存问题
go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/heap"
排查协程问题
go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/goroutine"
排查锁问题
go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/mutex"
排查阻塞问题
go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/block"