这是我参与「第三届青训营 -后端场」笔记创作活动的第3篇笔记。
1.什么是高质量
代码正确可靠、简洁清晰
2.编程原则:
简单性: 消除多余的复杂性,以简单清晰的逻辑编写代码
可读性: 写给人看的,可维护代码第一步是确保代码可读
生产力: 团队整体工作效率很重要
3.编码规范:
3.1.代码格式:
- 使用gofmt自动格式化代码
3.2.注释:
-
解释代码作用、如何做的、实现的原因、什么情况会出错。
-
应提供代码未表达出来的上下文信息
3.3.变量命名:
-
简洁胜于冗长。
-
缩略词全大写,当其处于开头且不需要导入使用全小写。
-
变量距离其被使用的地方越远,则需要携带更多的上下文信息。
3.4.函数命名:
-
函数名不携带包名的上下文信息。
-
函数名尽量简短。
-
如果包名和函数返回类型不同时,可以在函数名中加入类型信息
3.5.package命名:
-
只有小写字母组成,不包含大写字母和下划线等字符;
-
简短并包含一定的上下文信息;
-
不要和标准库同名;
-
尽量不使用常用变量名作为包名;
-
尽量使用单数而不是复数;
-
谨慎使用缩写。
3.6.控制流程
-
避免嵌套,保持正常流程清晰
-
尽量保持正常代码路径为最小缩进
3.7.错误和异常处理
error:
-
简单错误优先使用errors.New来创建匿名变量来直接表示简单错误,有格式化需求用fmt.Errorf
-
错误的Wrapt提供了error嵌套的能力,可以生成一个error的跟踪链,在fmt.Errorf中使用%w将错误关联到错误链中
-
判定一个错误是否为特定错误,使用errors.ls,可以判定错误链上的所有错误是否含有特定的错误
-
在错误链上获取特定种类的错误,使用errors.As
panic:
-
用于真正异常的情况
-
不建议在业务代码使用panic,会直接停止程序
-
调用不包含recover会导致程序崩溃
-
若问题可以被屏蔽或解决建议使用error代替panic
-
当程序在启动阶段发生不可逆转的错误时,可以在init或者main函数中使用panic
recover:
-
只能在被defer的函数中使用
-
嵌套无法生效
-
只能在当前goroutine生效
-
defer后进先出
-
需要更多上下文信息,可以recover后在log中记录当前的调用栈
4.性能优化
4.1.Benchmark
func BenchmarkFib20(b *testing.B) //基准测试函数名格式
go test-bench //接受一个正则表达式来匹配相应的基础测试名
go test -bench=. //跑全部的基本测试
4.2.slice预分配内存
-
尽可能在使用make()初始化切片时提供容量信息,减少内存分配次数
-
在已有切片基础上创捷切片,不会创建新的底层数组,原数组内存有引用得不到释放,使用copy代替re-slice
4.3.map预分配内存
- 尽可能在使用make()初始化切片时提供容量信息,减少内存分配次数
4.4.字符串处理
-
使用+拼接性能最差,string.Builder,bytes.Buffer相近,string.Builder更快
-
尽量使用strings.Builder来拼接字符串
-
已知需要分配容量可以使用builder.Grow()或者buf.Grow()来进一步提高性能
4.5.空结构体
-
几乎不占任何内存空间
-
可作为各种场景下的占位符
4.6.atomic包
-
多线程编程中使用atomic包性能比加锁要更好
-
锁属于系统调用,atomic操作通过硬件实现
-
sync.Mutex用来保护一段逻辑,不仅仅用于保护一个变量
-
对于非数值操作,可以使用atomic.Value,能承载一个interface{}
5.性能调优原则
-
依靠数据而不是猜测
-
定位最大瓶颈而不是细枝末节
-
不要过早优化
-
不要过度优化
6.性能分析工具 pprof
6.1.pprof使用
浏览器查看指标在/debug/pprof目录下
topN命令: 展示占用CPU资源最多的函数
flat == cum,函数中没有调用其他函数;
flat == 0,函数中只有其他函数的调用。
list命令: 根据指定的正则表达式查找代码行
web命令: 通过可视化网页查看
6.2.排查CPU占用过高
go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/profile"
| 列名 |含义 |
| --- | --- | | flat | 当前函数本身的执行耗时 | | flat% | flat占CPU总时间的比例 | | sum% | 上面每一行的flat%总和 | | cum | 指当前函数本身加上其调用函数的总耗时 | | cum% | cum占CPU总时间的比例 |
6.3.排查堆内存Heap
go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/heap"
| 类型 | 含义 |
|---|---|
| alloc_object | 程序累计申请的对象数 |
| alloc_space | 程序累计申请的内存大小 |
| inuse_objects | 程序当前持有的对象数 |
| inuse_space | 程序当前占用的内存大小 |
6.4.排查goroutine协程泄露
go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/goroutine"
6.5.排查mutex锁的争用
go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/mutex"
6.6.排查阻塞操作
go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/block"