高质量编程&性能调优实战
1.高质量编程
1.1 编码规范
1.1.1 注释
- 应该解释代码作用->提供有用信息
- 注释公共符号
- 解释代码是如何做的
- 代码实现的原因
- 外部因素
- 提供额外上下文
- 什么情况下会出错
1.2.1 命名规范
- 变量
- 简介胜于冗长
- 缩略词全大写,但当其位于变量开头且不需要导出时,使用全小写
- 例如使用ServeHTTP而不是ServeHttp
- 使用XMLHTTPRequest或者xmlHTTPRequest
- 变量距离其被使用的地方越远,则需要携带越多的上下文信息
- 函数
- 函数名不携带包名的上下文信息,因为包名和函数名总是成对出现的
- 函数名尽量简短
- 包
- 只由小写字母组成。
- 不包含大写字母和下划线等字符简短并包含一定的上下文信息。例如schema、task 等不要与标准库同名。例如不要使用sync或者strings
1.2.2 控制流程
- 避免嵌套,保持正常流程清晰
- 尽量保持正常代码路径为最小缩进
1.2.3 错误和异常处理
- error尽可能提供简明的上下文信息链,方便定位问题
- panic用于真正异常的情况
- recover生效范围,在当前goroutine的被defer的函数中生效
1.3 性能优化建议
1.3.1使用Benchmark
1.3.2 Slice
- 尽可能在使用
make()
初始化切片时提供容量信息
切片本质是一个数组片段的描述,包括数组指针,片段长度和容量,创建切片会服用原来切片的底层数组
- 大内存未释放 - 可以使用copy代替re-slice
- 场景:
- 原切片较大,代码在原切片基础上新建小切片
- 原地城数组在内存中有引用,得不到释放
- 场景:
1.3.3 Map
map预分配内存
原因:不断向map中添加元素的操作会触发map的扩容提前分配好空间可以减少内存拷贝和Rehash的消耗建议根据实际需求提前预估好需要的空间
字符串处理
- 使用+拼接性能最差,strings.Builder,bytes.Buffer相近,strings.Buffer 更快,原因:
- 字符串在Go语言中是不可变类型,占用内存大小是固定的
- 使用+每次都会重新分配内存
- builder 和 buffer底层都是
[]byte
数组 - 内存扩容策略,不需要每次拼接重新分配内存
atomic包
- 硬件实现,效率比锁高
- 锁的实现通过操作系统,系统调用
1.4 小结
- 避免常见的性能郜陷阱可以保证大部分程序的性能
- 普通应用代码,不要一味地追求程序的性能
- 越高级的性能优化手段越容易出现问题
- 在满足正确可靠、简洁清晰的质量要求的前提下提高程序性能
2.性能调优实战
大部分都是实战内容。