高质量代码规范
- 注释
- 库中任何函数都必须注释
- 任何不明显也不简短的功能必须注释
- 在一个包中声明的函数、常量、变量和结构体都要注释
- 函数应当描述自己的输入、作用、预期输出等
注释应当具有以下作用:
1.1 注释应当做到的- 解释代码做的是什么
- 解释代码如何运行的
- 解释代码实现的原因,为什么在这里要这么写
- 解释调用代码的限制条件和在不遵守调用规范时会出现什么问题
- 公共符号也要注释
- 代码格式
gofmt 自动格式化代码的工具
goimports 包管理工具
3. 命名规范
- 变量名
- 简洁胜于冗长
- 简称全大写,当缩略词位于变量开头且无需导出则可使用全小写
- 用变量用的越远(越偏僻的变量),应当携带更多的上下文信息
- 函数名
- 尽量简短
- 不必包含包的信息,因为包名和函数类型总会一起出现。
- 当返回的类型与包名一致时,可省略类型信息,不一致时则需要包含
- 包名
- 仅包含小写字母
- 简短且包含一定的上下文
- 不能与标准库重名
- 绕开常用变量名
- 使用单数
- 谨慎地使用缩写
- 编码规范
- 优先处理错误和特殊情况,一旦出现直接结束调用并返回
err而非判断接判断接判断接判断。。。,减少嵌套。
4.1 错误处理 - error
- 错误相关的wrap和unwrap
这两个中的wrap提供了一个err嵌套另一个err的能力,生成一个err的跟踪链路,方便措施排查,可使用fmt.Errorf("%w",err)即使用%w关键字关联它。 - errors.Is(),可判定某个错误是否为特定错误,也可判定错误链上是否含有特定种类的错误
- errors.As(),可获取特定种类错误的路径
- 错误相关的wrap和unwrap
- panic()
- 当程序在启动发现了无法逆转的致命错误时,可在初始化(
init)或者main函数中使用panic - 平时尽量别用
- 当程序在启动发现了无法逆转的致命错误时,可在初始化(
recover:出现pannic时用的(什么东西?)生效于当前的goroutine的被defer的函数
性能优化
保证正确运行
定位主要瓶颈再优化
benchmark
使用 go提供的benchmark工具可得到一个结果
从左到右依次为测试函数名-CPU核数、执行次数、每次执行花费时间、每次执行申请的内存大小、每次执行申请内存的次数
Tips : 尽量减少内存分配的次数
关于切片的优化建议
- 尽可能在初始化时指定切片大小(
make([]Type,len)),可以极大的减小执行时间(主要是减少内存分配的次数) - 在对切片中部分值进行取用时,尽量先新建一个切片,再使用copy获取对应位置的值再用于返回或者读取;而非直接截取该切片所需位置的值用于使用
原因:直接截取时go会复用原切片的底层数组,多次取用时,如果原切片的大小较大,底层数组所占内存也会很大,这时由于采用的是复用机制,内存占用也会很大且不会被释放,采用cpoy则会明显改善这个问题
tips:关于切片的取用,[:]左右两边的默认值分别为0和切片的当前长度,当对:两边的的数字进行修改时则按修改的数字取对应的位数
关于map
也建议在已知大概容量的情况下预分配大小。map_variable:=make(map[KeyType]ValueType,initialCapacity )
关于字符串
拼接
常见的拼接方式有三种,strings.Builder、+、ByteByffer
拼接操作中直接使用+号的性能最差,建议使用strings.Builder,bytebuffer稍慢于strings.Builder
使用+号的执行效率很差,原因是在go中,字符串是不可变类型,每次使用
+号都会重新分配内存,时间会变得很长,而另外两个底层使用的[]byte数组,故性能更好。
Grow()方法:后两种方法都有这个方法,Grow(n*len(str))相当于预分配大小
关于空结构体
空结构体相较布尔变量还可节省一部分空间,在某些场景的map[][]相关操作可能会用到
性能分析工具
- pprof
使用简介?
go tool pprof PPROFURL/api
cpu相关
执行
go tool pprof PPROFURL/profile?seconds=<TIME>
#<TIME>就是秒数
top
当正常进入类似(pprof)的软件后
输入top会得到一个列表
| flat | flat% | sum% | cum | cum% |
|---|---|---|---|---|
| 当前函数本身执行耗时 | flat占cpu总时间的比例 | 上面每一行flat的总和 | 当前函数本身加上其调用函数的总耗时 | cum占用cpu的总时间的比例 |
list
当使用top定位到问题函数后
使用list <Targetfunc>就可以查看该函数中每一行代码的详细占用时间。
内存相关
使用例子
go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/heap"
此时访问localhost:8080就可查看堆内存相关的页面了。
和上面相同,top可查看类似的占用列表,而和cpu不同的是,查看代码的占用内存时需要使用source命令
页面样的SAMPLE选项
localhost:8080/ui上存在一个SAMPLE按钮,按下后会出现alloc_objects(程序累计申请的对象数)、alloc_space(程序累计申请的内存大小)、inuse_objects(程序当前使用的对象数)、inuse_space(程序当前占用的内存大小)
goroutine协程
使用例子
go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/goroutine"
常用火焰图进行直观的动态展示
找到对应的问题函数后使用source可定位到问题代码。
mutex-锁
使用例子
go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/mutex"
依然是使用source进行定位
block-阻塞
同上,只需将pprof后的内容换成block就行
上面可去掉-http选项,此时展示的就是控制台信息了
pprof会过滤掉一些占用很小的函数,若要查看全量的信息,则可以在proof主页面上直接查看