这是我参与「第五届青训营 」伴学笔记创作活动的第 4 天
Go 高质量编程与性能调优
今天的笔记偏向于文档。
高质量编程
简介
什么是高质量? --编写的代码能够达到正确可靠、简洁清晰的代码是高质量代码。
- 各种边界条件是否考虑完备
- 异常情况处理,稳定性保证
- 易读易维护
编码规范
代码格式
注释
- 注释应该解释代码作用
- 注释应该解释代码如何做的
- 注释应该解释代码实现的原因
适合解释代码的外部因素,提供额外的上下文
- 注释应该解释代码什么情况下会出错
公共符号始终要注释
反例:
命名格式
- variable
- function
- package
控制流程
- 避免嵌套,保持正常流程清晰
- 尽量保持正常代码为最小缩进
控制流程小结:
- 线性原理,处理逻辑尽量走直线,避免复杂的嵌套分支。
- 正常流程代码沿着屏幕向下移动。
- 提升代码可维护性和可读性。
- 故障问题大多出现在复杂的条件语句和循环语句中。
错误和异常处理
- 简单错误
- 错误的Wrap和Unwrap
- 错误判定
- panic
- recover
小结:
- error尽可能提供简明的上下文信息链,方便定位问题
- panic用于真正异常的情况
- recover生效范围,在当前的goroutine的被defer的函数中生效
性能优化建议
Benchmark
下载代码,拷贝到本地
func Fib(n int) int {
if n < 2 {
return n
}
return Fib(n-1) + Fib(n-2)
}
import "testing"
func BenchmarkFib10(b *testing.B) {
for n := 0; n < b.N; n++ {
Fib(10)
}
}
slice
- Slice 预分配内存
主要是避免了扩容的复制时间
map
- map 预分配空间
字符串处理
使用srings.builder和直接字符相加和buff的对比
底层分析,buffer多申请了一块内存,builder是unsafe的,少申请一次内存
空结构体
使用空结构体可以节省内存
atomic包
小结:
- 避免常见的性能陷阱可以保证大部分程序的功能
- 普通应用代码,不要一味地追求程序的性能
- 越高级的性能优化手段越容易出问题
- 在满足正确可靠、简洁清晰的质量要求的前提下提高程序性能
性能调优实战
性能调优简介
- 要依靠数据不是猜测
- 要定位最大瓶颈而不是细枝末节
- 不要过早优化
- 不要过度优化
pprof实战
运行程序
运行提供实验代码 然后打开这个地址
go tool pprof "http://localhost:6060/debug/pprof/profile?seconds=10",查看CPU的占用,top是查看占用资源的函数
然后可以看到Tiger.eat函数消耗资源最多
然后可以使用list命令,根据指定的正则表达式查找代码行
堆
占用了两个多G的内存,刚才我们使用的是pprof终端的方式,不是很明确,这时我们可以通过页面查看。而且里面的内容都是和内存占用相关的,因为最后的后缀是heap。
go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/heap"
其中http就是要新打开的端口,执行命令后会弹出页面:
协程
goroutine泄露也会导致内存泄露。
也可以通过火焰图来查询
小结: