高质量编程与性能调优实战| 青训营笔记

160 阅读4分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的第3篇笔记。

1.什么是高质量

代码正确可靠、简洁清晰

2.编程原则:

简单性: 消除多余的复杂性,以简单清晰的逻辑编写代码

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

生产力: 团队整体工作效率很重要

3.编码规范:

3.1.代码格式:

  • 使用gofmt自动格式化代码

3.2.注释:

  • 解释代码作用、如何做的、实现的原因、什么情况会出错。

  • 应提供代码未表达出来的上下文信息

3.3.变量命名:

  • 简洁胜于冗长。

  • 缩略词全大写,当其处于开头且不需要导入使用全小写。

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

3.4.函数命名:

  • 函数名不携带包名的上下文信息。

  • 函数名尽量简短。

  • 如果包名和函数返回类型不同时,可以在函数名中加入类型信息

3.5.package命名:

  • 只有小写字母组成,不包含大写字母和下划线等字符;

  • 简短并包含一定的上下文信息;

  • 不要和标准库同名;

  • 尽量不使用常用变量名作为包名;

  • 尽量使用单数而不是复数;

  • 谨慎使用缩写。

3.6.控制流程

  • 避免嵌套,保持正常流程清晰

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

3.7.错误和异常处理

error:

  • 简单错误优先使用errors.New来创建匿名变量来直接表示简单错误,有格式化需求用fmt.Errorf

  • 错误的Wrapt提供了error嵌套的能力,可以生成一个error的跟踪链,在fmt.Errorf中使用%w将错误关联到错误链中

  • 判定一个错误是否为特定错误,使用errors.ls,可以判定错误链上的所有错误是否含有特定的错误

  • 在错误链上获取特定种类的错误,使用errors.As

panic:

  • 用于真正异常的情况

  • 不建议在业务代码使用panic,会直接停止程序

  • 调用不包含recover会导致程序崩溃

  • 若问题可以被屏蔽或解决建议使用error代替panic

  • 当程序在启动阶段发生不可逆转的错误时,可以在init或者main函数中使用panic

recover:

  • 只能在被defer的函数中使用

  • 嵌套无法生效

  • 只能在当前goroutine生效

  • defer后进先出

  • 需要更多上下文信息,可以recover后在log中记录当前的调用栈

4.性能优化

4.1.Benchmark

func BenchmarkFib20(b *testing.B)   //基准测试函数名格式

go test-bench       //接受一个正则表达式来匹配相应的基础测试名
go test -bench=.    //跑全部的基本测试

4.2.slice预分配内存

  • 尽可能在使用make()初始化切片时提供容量信息,减少内存分配次数

  • 在已有切片基础上创捷切片,不会创建新的底层数组,原数组内存有引用得不到释放,使用copy代替re-slice

4.3.map预分配内存

  • 尽可能在使用make()初始化切片时提供容量信息,减少内存分配次数

4.4.字符串处理

  • 使用+拼接性能最差,string.Builder,bytes.Buffer相近,string.Builder更快

  • 尽量使用strings.Builder来拼接字符串

  • 已知需要分配容量可以使用builder.Grow()或者buf.Grow()来进一步提高性能

4.5.空结构体

  • 几乎不占任何内存空间

  • 可作为各种场景下的占位符

4.6.atomic包

  • 多线程编程中使用atomic包性能比加锁要更好

  • 锁属于系统调用,atomic操作通过硬件实现

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

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

5.性能调优原则

  • 依靠数据而不是猜测

  • 定位最大瓶颈而不是细枝末节

  • 不要过早优化

  • 不要过度优化

6.性能分析工具 pprof

6.1.pprof使用

浏览器查看指标在/debug/pprof目录下

topN命令: 展示占用CPU资源最多的函数

flat == cum,函数中没有调用其他函数;

flat == 0,函数中只有其他函数的调用。

list命令: 根据指定的正则表达式查找代码行

web命令: 通过可视化网页查看

6.2.排查CPU占用过高

go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/profile"

| 列名 |含义  |

| --- | --- | | flat | 当前函数本身的执行耗时 | | flat% | flat占CPU总时间的比例 | | sum% | 上面每一行的flat%总和 | | cum | 指当前函数本身加上其调用函数的总耗时 | | cum% | cum占CPU总时间的比例 |

6.3.排查堆内存Heap

go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/heap"
类型含义
alloc_object程序累计申请的对象数
alloc_space程序累计申请的内存大小
inuse_objects程序当前持有的对象数
inuse_space程序当前占用的内存大小

6.4.排查goroutine协程泄露

go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/goroutine"

6.5.排查mutex锁的争用

go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/mutex"

6.6.排查阻塞操作

go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/block"