这是我参与「第三届青训营 -后端场」笔记创作活动的的第3篇笔记」
高质量编程
高质量:编写的代码能够达到正确可靠、简洁清晰的目标。
- 各种边界条件是否考虑完备
- 异常处理,保证稳定性
- 易读易维护 通用原则
- 简单性
- 容易理解 逻辑清晰
- 可读性
- 生产力
- 提高团队整体工作效率
编码规范
- 代码格式
- gofmt自动格式化代码
- 注释
- 代码作用,解释公共常量、公共变量、函数、结构体等
- 代码如何做
- 代码实现原因
- 代码什么情况下会出错
- 命名规范
- 参数名表示实际功能比较好
- 变量
- 缩略词全大写
- 变量距离其被使用的地方越远,需要携带悦动上下文信息
- 函数
- 不需要携带包名信息,实际调用时会 包名.函数名
- 包
- 只由小写字母组成,无下划线
- 单数
- 不使用常见变量名
- 简短并包含上下文信息
- 控制流程
- 避免分支上的嵌套
- 减少循环、嵌套,优先处理错误或特殊情况
- 错误和异常处理
- fmt.Errorf中使用%关键字来将一个错误关联至错误链中
- 错误链 errors.ls()
- 获取特定种类的错误 errors.As()
- 不建议在业务代码中使用panic,在程序启动阶段可能发生不可逆转的错误时 可在init 或 main中用panic
- recover 只能在当前goroutine生效,在defer中用,可在recover后在log中记录当前的调用栈 多个defer是后进先出,defer语句会在函数返回前调用
性能优化建议
如何评估
go test -bench=. -benchmem
优化建议
- slice切片,尽可能在使用make()初始化切片时提供容量信息(预分配内存)
data := make([] int, 0, size)- 数组容量不够时,要先扩容才插入新数据
- 避免大内存未释放,使用copy代替re-slice
- map预分配内存
- 无预分配,添加元素触发扩容
- 减少内存拷贝和rehash的消耗
- 字符串处理
- 代替+, strings.Builder 处理拼接字符串(和java类似)
- 使用空结构体节省内存,仅作占位符
- 实现Set可用map代替,且只用到key, value可用空结构体
m := make(map[int]struct{}) m[i] = struct{}{} - atomic包 原子操作
- 比直接用sync.Mutexlock加锁要高效,锁属于系统调用
性能调优实战
简介
- 调优原则
-
要依靠数据不是猜测
-
要定位最大瓶颈而不是细枝末节
-
不要过早优化
-
不要过度优化
-
性能分析工具 pprof
调优案例
- 流程
- 建立服务性能评估手段
- 分析性能数据,定位性能瓶颈
- 重点优化项改造
- 优化效果验证