这是我参与「第五届青训营 」伴学笔记创作活动的第 3 天
通过今天的学习,我收获到了
- 如何编写更简洁清晰的代码
- 常用Go语言程序优化手段
- 熟悉Go程序性能分析工具
- 了解了工程中性能优化的原则和流程
----------------------------学习笔记------------------------------
1. 高质量编程
1.1 高质量编程简介
- 正确性:是否考虑各种边界条件,错误的调用是否能够处理
- 可靠性:异常情况或者错误的处理策略是否明确,依赖的服务出现异常是否能够处理
- 简洁:逻辑是否简单,后续调整功能或新增功能是否能够快速支持
- 清晰:其他人在阅读理解代码的时候是否能清楚明白,重构或者修改功能是否不会担心出现无法预料的问题
编程原则:
1.2 编码规范
1.2.1 代码格式
1.2.2 注释
小结:
- 代码是最好的注释
- 注释应该提供代码未表达出的上下文信息
1.2.3 命名规范
变量命名规范:
函数命名规范:
包命名规范:
小结:
- 核心目标是降低阅读理解代码的成本
- 重点考虑上下文信息,设计简洁清晰的名称
1.2.4 控制流程
小结:
- 线性原理,处理逻辑尽量走直线,避免复杂的嵌套分支
- 正常流程代码沿着屏幕向下移动
- 提升代码可维护性和可读性
- 故障问题大多出现在复杂的条件语句和循环语句中
1.2.5 错误和异常处理
小结:
- error尽可能提供简明的上下文信息链,方便定位问题
- panic用于真正异常的情况
- recover生效范围,在当前goroutine的被defer的函数中生效
知识点:defer生命的语句执行顺序,其实是放入了一个栈中,程序执行结束之前顺序出栈
package main
import "log"
func main() {
if true {
defer log.Println("1")
} else {
defer log.Println("2")
}
defer log.Println("3")
}
运行结果:
31
1.3 性能优化建议
注意:性能优化的前提是满足正确可靠、简洁清晰等质量因素. 性能优化是综合评估,有时候时间效率和空间效率可能对立
Benchmark:Benchmark是Go语言提供了支持基准性能测试的benchmark工具
以下代码是利用Benchmark对Fib()方法进行基准测试
package benchmark
import "testing"
func Fib(n int) int {
if n < 2 {
return n
}
return Fib(n-1) + Fib(n-2)
}
func BenchmarkFib(b *testing.B) {
for i := 0; i < b.N; i++ {
Fib(10)
}
}
结果:
goarch: amd64
pkg: github.com/wolfogre/go-pprof-practice/benchmark
cpu: Intel(R) Core(TM) i5-10200H CPU @ 2.40GHz
BenchmarkFib
BenchmarkFib-8 4894159 238.8 ns/op
PASS
Process finished with the exit code 0
BenchmarkFib是测试函数名,-8表示GOMAXPROCS的值(默认为CPU核数)4894159表示一共执行了4894159次,即b.N的值238.8 ns/op表示每次执行花费238.8ns
预分配内存(此处没有实际测试,参考课件代码)
slice预分配内存:
map预分配内存:
字符串拼接优化
package benchmark
import (
"strings"
"testing"
)
func Plus(n int, str string) string {
s := ""
for i := 0; i < n; i++ {
s += str
}
return s
}
func StrBuilder(n int, str string) string {
var builder strings.Builder
for i := 0; i < n; i++ {
builder.WriteString(str)
}
return builder.String()
}
func BenchmarkPlus(b *testing.B) {
for i := 0; i < b.N; i++ {
Plus(10, "a")
}
}
func BenchmarkStrBuilder(b *testing.B) {
for i := 0; i < b.N; i++ {
StrBuilder(10, "a")
}
}
两个测试函数运行结果:
BenchmarkPlus
BenchmarkPlus-8 4732092 253.0 ns/op
BenchmarkStrBuilder
BenchmarkStrBuilder-8 17753370 56.61 ns/op
很明显,使用 + 运算符拼接字符串的效率远不及strings.Builder拼接字符串.
其实, 当使用 + 拼接 2 个字符串时,生成一个新的字符串,那么就需要开辟一段新的空间,新空间的大小是原来两个字符串的大小之和。拼接第三个字符串时,再开辟一段新空间,新空间大小是三个字符串大小之和,以此类推
为什么sringbuilder会比bytebuffer更快一些,以下是二者的源码:
空结构体
atomic包