这是我参与「第五届青训营 」伴学笔记创作活动的第 3 天
高质量编程与代码规范 | 性能优化 | 青训营笔记
高质量编程
目标:正确可靠、简洁清晰
- 边界条件是否完备
- 异常处理,稳定性保证
- 易读易维护
规范
- 公共符号(变量、常量、函数)始终要注释,提供额外的上下文信息。应该解释:1)代码作用 ;2)如何做的; 3)实现的原因;4)什么情况会报错
- 代码格式:推荐gofmt自动格式化代码,goimports进行依赖包管理
命名规范
控制流程
- 避免分支嵌套
- 尽量保持正常代码路径为最小缩进(优先处理异常和特殊情况)
- 线性原理,处理逻辑尽量走直线,正常代码流程沿着屏幕向下移动
错误可异常处理规范
- 简单错误(仅出现一次,在其他地方不需要捕获)优先使用
errors.New来创建匿名变量直接表示简单错误,如果有格式化需求使用fmt.Errorf - error的跟踪连可用warp
- 判定是否为特定错误使用
errors.Is - 获取特定种类错误,使用
errors.As
- 不建议在业务代码中使用
panic,只适用于真正异常,不启动没法运行的情况 recover:只能在被defer的函数中使用,嵌套无法生效,只在当前goroutine生效。打印panic上下文,在log中记录调用栈。- defer语句会在函数返回前调用,多个defer语句是后进先出
性能优化
如何使用?
要用实际数据衡量。Go提供了支持基准性能测试的benchmark工具
go test -bench=. -benchmem
性能优化建议
- slice预分配内存:尽量在初始化时制定容量,减少获取内存分配次数
- 创建一个新的切片会复用原来切片的底层数组。
- map预分配内存:make预分配大小,不断向map添加元素会触发扩容
- 字符串处理:直接相加性能差,最好使用
strings.Builder(更高效)或者bytes.Buffer
-
空结构体节省内存 可以用map实现set,因为只需要map的键,而不需要值
m := make(map[int]struct{}) -
多线程
用atomic包比加锁要好。因为锁是通过系统实现,属于系统调用,atomic操作通过硬件实现,效率比锁高。仅保护一个变量可考虑用atomic包,sync.Mutex应该用于保护一段逻辑。
性能调优实战
原则
- 依靠数据而不是猜测
- 定位瓶颈而不是细节
- 不要过早优化
- 不要过度优化