这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天
掘金字节内部课1月17日:高质量编程简介及编码规范, 性能优化指南, 性能优化分析工具, 性能调优实战案例
一、本堂课重点内容:
- 如何编写简洁清晰的代码
- 常用Go语言优化手段
- 熟悉Go程序性能分析工具
- 了解工程中性能优化的原则和流程
二、详细知识点介绍:
1. 高质量编程
高质量编程简介、编码规范、性能优化建议
1.1 简介
边界条件;异常情况处理,稳定能保证;易读易维护。
原则:简单性(逻辑)、可读性、生产力(团队效率)。——Go语言开发者 Dave Cheney
1.2 编码规范
1.2.1 编码规范-代码格式:格式化工具gofmt,依赖管理工具goimports
1.2.2 编码规范-注释:
库中任何函数必须注释,公共符号需要注释
注意应解释代码的:
- 作用(适于公共符号)
- 如何做的(相对复杂、不明显的逻辑)
- 实现的原因(解释代码的外部因素,提供额外上下文)
- 什么情况会出错(解释代码限制条件)
1.2.3 编码规范-命名规范
- 缩略词全大写,但其位于变量开头且不需要导出时,使用全小写:eg.use
ServerHTTPnotServeHttp, useXMLHTTPRequestorxmlHTTPRequest. - 变量距离其使用的位置越远,需要携带越多的上下文信息(方便辨认)
- package:只由小写字母组成,不包含大写字母和下划线;使用单数而非复数;谨慎使用缩写eg.
format->fmt
1.2.4 编码规范-控制流程:优先处理错误/特殊情况
1.2.5 编码规范-错误和异常处理
- 简单错误使用
errors.New或fmt.Errorf - 错误的Wrap(一个error嵌套另一个error,形成跟踪链)和Unwrap。eg.
fmt.Errorf中使用%w关键字 进行关联 - 错误判定:是否为特定错误使用
errors.Is,错误链上获取特定种类错误使用errors.As(可取出错误位置) panic:慎用(启动阶段发生不可逆转错误需尽早暴露时)recover:只能在被defer的函数中使用;嵌套无法生效;只在当前goroutine生效;defer语句是后进先出。
1.3 性能优化建议
- 自带工具
Benchmark
slice:预分配内存;大内存未释放(在已有切片上创建切片,不会创建新的底层数组)——用copy代替map:预分配内存- 字符串处理:拼接使用
string.Builder≈bytes.Buffer优于+(字符串在Go中是不可变类型,占用内存大小固定;使用+每次都会重新分配内存;string.Builder和bytes.Buffer底层都是[]byte数组,使用内存扩容策略),string.Builder比bytes.Buffer稍快;使用预分配进一步提升效率。 - 空结构体节省内存:
struct{}实例不占据任何内存空间;可作为占位符使用;实现Set(只需要map的键) atomic包:锁是操作系统实现,属于系统调用;atomic操作是硬件实现,效率比锁高;sync.Mutex应用来保护一段逻辑而非仅仅是一个变量;对于非数值操作可使用atomic.Value,能承载一个interface{}
2. 性能调优实战
性能调优简介、性能分析工具pprof实战、性能调优案例
2.1 简介
要依靠数据;定位最大瓶颈而非细枝末节;不要过早优化(早期迭代);不要过度优化
2.2 性能分析工具pprof
2.2.1 性能分析工具pprof工具-功能简介
2.2.2 性能分析工具pprof工具-排查实战
实践项目:go-pprof-practice
2.2.3 性能分析工具pprof工具-采样过程和原理
2.3 性能调优案例
2.3.1 业务服务优化
- 建立服务性能评估手段
- 分析性能数据,定位瓶颈
- 重点优化项改造
- 优化效果评估
2.3.2 基础库优化
AB实验SDK的优化:
- 分析基础库核心逻辑和性能瓶颈
- 设计完善改造方案
- 数据按需获取
- 数据序列化协议优化
- 内部压测验证
- 推广业务服务落地验证
2.3.3 Go语言优化
编译器&运行时优化:
- 优化内存分配策略
- 优化代码编译流程,生成更高效的程序
- 内部压测验证
- 推广业务服务落地验证
优点:
- 接入简单,只需要调整编译配置
- 通用性强
2.4 总结
- 性能调优原则
- 要依靠数据不是猜测
- 性能分析工具 pprof
- 熟练使用pprof 工具排查性能问题并了解其基本原理
- 性能调优
- 保证正确性
- 定位主要瓶颈