这是我参与「第五届青训营 」伴学笔记创作活动的第 3 天
本堂课知识点:
高质量编程简介及编码规范
本节主要简要介绍了高质量编程的定义和原则,分享了代码格式、注释、命名规范、控制流程、错误和异常处理五方面的常见编码规范。
1.1 高质量
编写的代码能够达到正确可靠、简洁清晰的目标可称之为高质量代码
各种边界条件是否考虑完备
异常情况处理,稳定性保证
易读易维护
编程原则:
简单性:简单清晰的逻辑,易理解
可读性:以人为本
生产力:团队合作
1.2 编码规范
编写高质量的Go代码 代码格式、注释、命名规范、控制流程、错误和异常处理
1.2.1 代码结构
gofmt自动格式化代码 goimports依赖包管理
1.2.2 注释
作用;怎么做的;代码实现的原因;可能出现的错误 公共符号始终要注释:包中声明的每个公共符号;不明显不简短的公共功能;库中的任何函数
1.2.3 命名规范
变量: 简洁胜于冗长;缩略词全大写HTTP;全局变量或者变量距离其被使用的地方越远,则需要携带更多的上下文信息
// 正确
func (c *Client) send(req *Request,deadline time.Time)
// 错误
func (c *Client) send(req *Request,t time.Time)
函数: 函数名不携带包名的上下文信息;尽可能简短;当名为 foo 的包某个函数返回类型 Foo 的包某个函数返回类型 Foo 时,可以省略类型信息而不导致歧义;当名为 foo 的包某个函数返回类型 Foo 的包某个函数返回类型 T 时,可以在函数名中加入类型信息
包: 小写字母;简短并包含一定的上下文信息;不要与标准库同名
1.2.4 控制流程
避免嵌套,保持正常流程清晰;尽量保持正常代码路径为最小缩进,优先处理错误情况/特殊情况,并尽早返回或继续循环来减少嵌套,增加可读性
1.2.5 错误和异常处理
简单错误: 优先使用 errors.New 来创建匿名变量来直接表示该错误。有格式化需求时使用 fmt.Errorf
错误的 Wrap 和 Unwrap: 错误的 Wrap 实际上是提供了一个 error 嵌套另一个 error 的能力,从而生成一个 error 跟踪链;在 fmt.Errorf 中使用 %w 关键字来将一个错误 wrap 至其错误链中
错误判定: errors.ls:可以判定错误链上所有的错误是否含有特定的错误; errors.As:在错误链上获取特定种类的错误
panic: 不建议在业务代码中使用 panic;如果当前 goroutine 中所有 deferred 函数都不包含 recover 就会造成整个程序崩溃;问题可以被屏蔽,error 代替 panic;当程序启动阶段发生不可逆转的错误时,可以在 init 或 main 函数中使用 panic
recover: recover 只能在被 defer 的函数中使用,嵌套无法生效,只在当前 goroutine 生效;如果需要更多的上下文信息,可以 recover 后在 log 中记录当前的调用栈
1.3性能优化
1.3.1 Benchmark工具
benchmark工具用于基准性能测试,go test -bench=. -benchmem
1.3.2 Slice预分配内存
尽可能在使用 make() 初始化切片时提供容量信息
// 切片
type slice struct {
array unsafe.Pointer
len int
cap int
}
另一个陷阱:大内存得不到释放 在已有切片的基础上进行切片,不会创建新的底层数组。 原切片较大,在原切片的基础上切片;底层数组在内存中仍然占据了大量空间,得不到释放。 使用 copy 替代 re-slice
1.3.3 Map预分配内存
不断向 map 中添加元素的操作会触发 map 的扩容; 根据实际需求提前预估好需要的空间; 提前分配好空间可以减少内存拷贝和 Rehash 的消耗
1.3.4 字符串处理 strings.Buillder
字符串拼接:字符串在 Go 语言中是不可变类型,占用内存大小是固定的
1.3.5 空结构体
节省内存空间,仅作为占位符
1.3.6 atomic包
与线程相关,通过硬件实现,效率比锁高
性能调优
2.1 性能调优原则
要依靠数据不是猜测 要定位最大瓶颈而不是细枝末节 不要过早优化 不要过度优化
2.2 性能分析工具 pprof
浏览器查看指标
CPU: flat:当前函数执行耗时 flat%:flat占CPU总时间比例 cum:当前函数加上其调用函数的总耗时
list命令: 根据指定的正则表达式查找代码行
web命令: 调用关系可视化
Heap-堆内存
goroutine-协程 go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/goroutine"
mutex-锁 go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/mutex"
block-阻塞
2.2.3 采样过程和原理
CPU采样: 函数对象和它们占用的时间
Heap-堆内存: 采样程序通过内存分配器在堆上分配和释放的内存,记录分配/释放的大小和数量
协程和ThreadCreate-线程创建:
Block-阻塞和Mutex-锁:
2.3 性能调优案例
2.3.1 业务服务优化
流程: 建立服务性能评估手段;分析性能数据,定位性能瓶颈;重点优化项改造;优化效果验证
2.3.2 基础库优化
AB实验SDK的优化
编译器和运行时优化
本堂课知识要点: 规范编码;性能调优;基础库优化
课后个人总结:
今天学习了高质量编程的定义和原则,包括代码格式、注释、命名规范、控制流程、错误和异常处理。学习了提高程序效率的性能优化的方法。还学习了性能调优原则和pprof工具的功能、实践应用以及采样过程和原理。以及了解了业务优化、基础库优化和Go语言优化的流程和方式。Go语言编码规范和其他编程语言还是有共同点的,所以理解起来并不难。我觉得性能优化知识点比较难掌握,然后我认为性能调优案例分析是今天学习的难点,需要实际运行代码加以理解。