GO的代码规范和性能调优工具| 青训营笔记

75 阅读4分钟

这是我参与「第五届青训营 」笔记创作活动的第3天

高质量编程

高质量编程简介

--编写的代码能够正确可靠,简洁清晰的目标

边界条件是否考虑完备? 异常情况处理,稳定性保证 易读易维护

编程原则

简单性,消除“多余的复杂性”,不理解的代码是无法修复改进的

可读性,代码是给被人看的,编写可维护代码的第一步是确保代码可读

生产力,团队整体工作效率非常重要

代码格式

对剑使用gofmt自动格式化代码

注释

注释公共符号

注释实现过程

提供额外上下文,解释代码的外部因素

结束代码的限制条件,什么时候回出错

代码规范

命名规范

缩略词全大写,如果是不用导出的函数,函数名开头要小写

变量距离被使用的地方越远,则需要携带越多的上下文信息

函数名不携带包名的上下文信息,因为包名和函数名总是成对出现,函数名尽量简短

当名为foo的函数返回T类型时,可以在函数名中加入类型信息

package:只用小写字母,不包含大写字母和下划线等字符,简短并包含一定的上下文信息,例如schema,task等 不要与标准库同名,也不使用常用变量名去给包命名

流程

避免分支上的嵌套

尽量保持正常代码路径为最小缩进

错误和异常处理

简单错误:只出现一次,且在其他地方不需要捕获该错误,优先使用errors.New创建匿名变量来直接表示简单错误

Wrap & Unwrap :

错误的wrap提供一个error嵌套另一个error的能力,从而生成了一个error的跟踪链

在fmt.error中使用%W关键字来将一个错误关联至错误链中

性能优化建议

怎么评估代码性能?

Benchmark

Go语言提供了支持基准性能测试的benchmark工具

go test -bench=.运行

Slice

Slice预分配内存

尽可能在使用mark()初始化切片提供容量信息

  • 切片本质是一个数组片段的描述 包括数组指针,片段长度,片段容量
  • 切片操作并不复制切片指向的元素
  • 创建一个新的切片会复用原来切片的底层数组

陷阱:大内存未释放

在已有切片的基础上创建切片,不会创建新的底层数组

当原切片较大时,代码在原切基础上新建小切片,底层数组在内存中有引用,得不到释放

解决:用copy替代re-slice

空结构体

使用空结构体节省内存

空结构体实例不占用内存,可以在各种场景下当做占位符来用

atomic包

锁的实现时通过操作系统来实现,属于系统调用

atomic操作是通过硬件来实现,效率比锁搞

sync.Mutex应该用来保护一段逻辑,不仅仅用于保护一个变量

对于非数值操作,可以使用atomi.value,能承载一个interface{}

性能调优实战

性能调优原则

  • 依靠数据而不是猜测
  • 要定位最大瓶颈而不是细枝末节
  • 不要过早优化
  • 不要过度优化

性能调优简洁

性能分析工具pprof

希望知道应用在什么地方耗费了多少CPU,Memory

是用于可视化和分析性能分析数据的工具

排查实战

命令行分析

go tool pprof "[http://localhost:6060/debug/pprof/profile?seconds=10]"

CPU

命令:top查看占用资源最多的函数

什么情况下 Flat == Cum?函数中没有调用其他函数

什么时候Flat = 0,函数中只有其他函数的调用

list

web调用关系可视化,使用该命令进行调用关系可视化的时候,需要安装好graphviz并设置好环境变量,否则会出现"dot": executable file not found in %PATH%

调用关系图,火焰图

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"