高质量编程
编码规范
错误和异常处理
Wrap和Unwrap
fmt.Errorf %w 生成错误链
错误判定
errors.Is 判断制定类型的错误
获取特定种类的错误,errors.As
panic
不建议在业务代码中使用,如果不包含recover回造成崩溃
若可以被屏蔽或解决,应当用error代替panic
recover
只在当前goroutine生效,只在被defer的函数使用
可以处理出panic的上下文
func (t *treeFS) Open(name string) (f fs.File, err error){
defer func(){
if e:= recover(); e != nil {
f = nil
// 记录下当前的调用栈
err = fmt.Errorf("gifs panic: %v\n%s", e, debug.Stack())
}
}()
}
性能
Benchmark-性能优化建议
go test -bench=. -benchmem
运行时间、内存分配
slice
最好可以预分配,减少扩容开销,map同理
大内存未释放
在已有切片基础上创建切片,不会创建新底层数组
- 如果原切片较大,代码在原切片基础上新建小切片,那么原底层数组在内存中有引用,得不到释放
- 使用copy代替re-slice
func GetLastBySlice(origin []int) []int{
return origin[len(origin)-2:]
}
func GetLastByCopy(origin []int) []int{
res := make([]int, 2)
copy(res, origin[len(origin-2):])
return res
}
使用gotest测试go test -run=. -v
使用strings.Builder
string with + << bytes.Buffer < strings.Builder
每次+回重新分配内存,后者底层都是[]byte,维护扩容策略。bytes.Buffer
转换为字符串时重新申请了空间,strings.Builder直接将底层[]byte转换成字符串类型返回
使用空结构体
空结构体是一个占位符,不需要值,不占空间
- 实现Set,可以考虑用Map代替
atomic
线程安全的计数器,比加锁性能好很多。锁由os实现,属于系统调用;atomic使用硬件实现,效率更高。
性能调优工具 - pprof
pprof实验blog blog.wolfogre.com/posts/go-pp…
定位瓶颈
-
go tool pprof "http://localhost:6060/debug/pprof/profile?seconds=10"
-
-
-
排查 CPU 问题
-
命令行分析
- go tool pprof "http://localhost:6060/debug/pprof/profile?seconds=10"
-
top 命令
-
list 命令
-
熟悉 web 页面分析
-
调用关系图,火焰图
-
go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/cpu"
-
-
排查堆内存问题
- go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/heap"
-
排查协程问题
- go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/goroutine"
-
排查锁问题
- go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/mutex"
-
排查阻塞问题
- go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/block"
-
-