01高质量编程
1.1简介
什么是高质量
- 各种边界条件是否考虑完备
- 异常情况处理,稳定性保证
- 易读易维护
编程原则
- 简单性
- 可读性
- 生产力
1.2编码规范
如何编写高质量的Go 代码
-
代码格式: 推荐使用gofmt自动格式化代码
-
注释: 注释应该解释代码作用; 注释应该解释代码如何做的; 注释应该解释代码实现的原因; 注释应该解释代码什么情况会出错.
-
命名规范: 简洁胜于冗长; 缩略词全大写,但当其位于变量开头且不需要导出时,使用全小写; 变量距离其被使用的地方越远,则需要携带越多的上下文信息;
-
控制流程: 避免嵌套,保持正常流程清晰; 尽量保持正常代码路径为最小缩进;
-
错误和异常处理: error 尽可能提供简明的上下文信息链,方便定位问题; panic 用于真正异常的情况; recover 生效范围,在当前goroutine 的被defer 的函数中生效;
1.3性能优化建议
简介:
- 性能优化的前提是满足正确可靠、简洁清晰等质量因素
- 性能优化是综合评估,有时候时间效率和空间效率可能对立
- 针对Go语言特性,介绍Go相关的性能优化建议
1.3.1性能优化建议-Benchmark
- 性能表现需要实际数据衡量
- Go语言提供了支持基准性能测试的benchmark工具 结果说明
PS E:\Users\Dell\GolandProjects\pprof> go test -bench .
goos: windows
goarch: amd64
pkg: pprof
cpu: Intel(R) Core(TM) i5-7300HQ CPU @ 2.50GHz
BenchmarkFib10-4 3981487 297.2 ns/op
-
go test -bench .:这行输入的命令 -
goos: windows:这行显示运行基准测试的操作系统,此处为 Windows。 -
goarch: amd64:这行显示运行基准测试的机器架构,此处为 64 位 AMD 架构。 -
pkg: GoProject1:这行显示包含基准测试代码的包名,此处为 "pprof"。 -
cpu: Intel(R) Core(TM) i5-7300HQ CPU @ 2.50GHz:这行显示运行基准测试的机器 CPU 信息,包括 CPU 型号和时钟频率。 -
BenchmarkFib10-4:这行表示测试函数名,-4代表CPU核数,3981487表示一个执行了3981487次,每次执行花费 297.2 ns
1.3.2性能优化建议-slice
预分配内存
运行结果如下:
BenchmarkNoPreAlloc-4 145 7885452 ns/op
BenchmarkPreAlloc-4 661 1831792 ns/op
可以看到预分配内存后,性能更好。因此应尽可能在使用make()初始化切片时提供容量信息。
大内存未释放
当我们在已有切片基础上创建新的切片时,新切片并不会创建一个新的底层数组这种情况下,如果我们从一个大切片中截取出一个小切片,并且在代码中保留对大切片的引用,那么原底层数组将会一直存在于内存中,得不到释放.
优化建议:使用copy替代re-slice 为了避免上述陷阱.
1.3.3性能优化建议-map
- 不断向map中添加元素的操作会触发map的扩容
- 提前分配好空间可以减少内存拷贝和Rehash 的消耗
- 建议根据实际需求提前预估好需要的空间
1.3.4性能优化建议-字符串处理
-
使用
+拼接性能最差,strings.Builder,bytes.Buffer相近,strings.Builder更快 -
字符串在Go语言中是不可变类型,占用内存大小是固定的
-
使用
+每次都会重新分配内存 -
strings.Builder,bytes.Buffer底层都是[]byte数组。内存扩容策略,不需要每次拼接重新分配内存 -
bytes.Buffer转化为字符串时重新申请了一块空间
-
strings.Builder直接将底层的byte 转换成了字符串类型返回
-
预分配内存后,
strings.Builder,bytes.Buffer性能都有所提升
1.3.5性能优化建议-空结构体
- 空结构体 struct{}实例不占据任何的内存空间
- 可作为各种场景下的占位符使用
- 节省资源
- 空结构体本身具备很强的语义,即这里不需要任何值,仅作为占位符
1.3.6性能优化建议-atomic包
- 锁的实现是通过操作系统来实现,属于系统调用
- atomic操作是通过硬件实现,效率比锁高
- sync.Mutex应该用来保护一段逻辑,不仅仅用于保护一个变量
- 对于非数值操作,可以使用atomic.Value,能承载一个 interface{}
02性能调优实战
2.1简介
性能调优原则
- 要依靠数据不是猜测
- 要定位最大瓶颈而不是细枝末节
- 不要过早优化
- 不要过度优化
2.2性能分析工具pprof
2.2.1性能分析工具pprof-功能简介
2.2.2性能分析工具pprof-排查实战
首先从GitHub链接github.com/wolfogre/go… 下载代码。代码运行后打开终端,执行命令: go tool pprof http://127.0.0.1:8080/debug/pprof/profile?seconds=30
执行命令后结果如下
PS E:\Users\Dell\GolandProjects\go-pprof-practice> go tool pprof http://127.0.0.1:8080/debug/pprof/profile?seconds=30
Fetching profile over HTTP from http://127.0.0.1:8080/debug/pprof/profile?seconds=30
Saved profile in C:\Users\13286\pprof\pprof.samples.cpu.006.pb.gz
Type: cpu
Time: Aug 3, 2023 at 10:47am (CST)
Duration: 30.01s, Total samples = 50ms ( 0.17%)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof)
2.2.2性能分析工具pprof-排查实战
我们可以在交互界面输入top3来查看程序中占用CPU前5位的函数:
(pprof) top3
Showing nodes accounting for 50ms, 100% of 50ms total
Showing top 3 nodes out of 24
flat flat% sum% cum cum%
30ms 60.00% 60.00% 30ms 60.00% runtime.stdcall3
10ms 20.00% 80.00% 10ms 20.00% runtime.cgocall
10ms 20.00% 100% 10ms 20.00% runtime.gopark
- flat:当前函数占用CPU的耗时
- flat::当前函数占用CPU的耗时百分比
- sun%:函数占用CPU的耗时累计百分比
- cum:当前函数加上调用当前函数的函数占用CPU的总耗时
- cum%:当前函数加上调用当前函数的函数占用CPU的总耗时百分比
Flat == Cum,函数中没有调用其他函数;
Flat == 0,函数中只有其他函数的调用.
我们还可以使用list 函数名命令查看具体的函数分析
(pprof) list stdcall3
Total: 50ms
ROUTINE ======================== runtime.stdcall3 in C:\Users\13286\sdk\go1.19.11\src\runtime\os_windows.go
30ms 30ms (flat, cum) 60.00% of Total
. . 1108://go:cgo_unsafe_args
. . 1109:func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr {
. . 1110: mp := getg().m
. . 1111: mp.libcall.n = 3
. . 1112: mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
30ms 30ms 1113: return stdcall(fn)
. . 1114:}
(pprof)
我们还可以输入web,通过svg图的方式查看程序中详细的CPU占用情况.想要查看图形化的界面首先需要安装graphviz图形化工具。由于我是Windows系统,进入官网下载graphviz:graphviz.gitlab.io/download/
我安装后还是不能运行web命令,终端显示在path路径下没有找到graphviz.我想到path路径修改后,重启电脑才能生效.重启后果然可以运行
pprof也支持分析内存性能数据。
输入下面的命令会在网页中显示内存占用情况
go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/heap"
结果如图所示
在网页中还可以查看火焰图. 火焰图(Flame Graph)是 Bredan Gregg 创建的一种性能分析图表,因为它的样子近似火焰而得名。 点击图中的view,再点击Flame Graph,即可看到火焰图
结果如下,内存性能火焰图示例: