这是我参与「第五届青训营 」伴学笔记创作活动的第 3 天
1 Go高质量编程
1.1 高质量定义
-边界条件是否完备
-维护性,可读性,可读性
-异常情况处理
1.2 规范-注释
公共符号始终要注释
注释应该接受代码作用,如何做,实现的原因
1.3 规范-命名
-避免冗长的表达,比如说for循环中,内部变量简洁表达即可
-给外界调用的函数,通过参数名命名来实现更好的理解
1.4 规范-控制流程
-避免嵌套
-保持正常代码路径为最小路径(本质还是减少嵌套
1.5 规范-错误处理
-简单错误:err.new() 一次调用即可
-复杂错误: 错误链,fmt.Errorf中使用:%w关键字来将一个错误wrap至其错误链中
-错误判定: 除了 '==' 外,可以使用 errors.Is以及error.As
后者相比于前者在于AS会调取出指定类型的错误,并将错误赋值给定义好的变量,便于后续处理
-panic: 不建议在业务中直接使用,用于正真异常的情况
-recover: 只能在被defer中的函数使用,只在当前goroutien生效
2 性能调优
2.1 Benchmark
了解一下用法即可
2.2 Slice
-slice预分配内存:尽可能在使用make()初始化切片提供容量信息!(这个确实以前没注意过),原因是不提前确认容量信息的情况下,在append时容量不够的情况下,slice会发生内存的拷贝。
-大内存未释放:原切片较大时候,代码可能在原切片基础上新建小切片,导致原底层数组在内存中有引用,得不到释放,这个时候可以使用copy代替re-slice
2.3 Map
-map预分配内存:提前分配好空间,减少内存拷贝和Rehash的消耗
2.4 字符串处理
-使用string.Builder代替常规的+字符串拼接
func ByteBuffer(n int,str string) string{
buf :=new(bytes.Buffer)
for i:=0;i<n;i++{
buf.WriteString(str)
}
return buf.String()
}
复制代码
原因:拼接每次都会重新分配内存,stringbuilder本质是[]byte数组
string.Builder也有预分配,builder.Grow
2.5 空结构体
使用空结构体节省内存
空结构体不占据任何的内存空间,可以作为各种场景下的占位符使用。
举例:假如我们需要一个set,仅仅对key进行操作,那么就可以定义成m1这种方式,相比于m2更省空间。
m1:=make(map[int]struct{})
m2:=make(map[int]bool)
2.6 Atomici包
锁的实现是通过操作系统来完成的,属于系统调用
atomic包则是通过硬件实现,实现效率比锁要高
3 性能调优
3.1 原则
3.2 pprof
一个性能调优工具
直接上实战
-启动项目后登入:http://localhost:6060/debug/pprof/