这是我参与「第三届青训营 -后端场」笔记创作活动的的第3篇笔记。
前言
如何编写更简洁清晰的代码?学习常用Go语言程序优化手段,学习使用Go程序性能分析工具。最后了解工程中性能优化的流程和其中的原则。
高质量编程
1、高质量编程简介
什么是高质量代码?
1-正确可靠为前提,即核心功能+各种边界条件考虑完善;
2-简洁清晰的目标,即易读易维护(逻辑清晰+命名规范)。
高质量代码有什么用?
1-逻辑清晰,命名规范,就会让扩展维护成本低。
2-正确可靠,无bug,就会让团队合作流畅,团队整体工作效率才是生产力。
高质量代码的原则?
1-简单性,消除“多余的复杂性”,即一些可知的上下文,拒绝冗余信息。
2-可读性,维护扩展代码的基础就是读代码。
2、编码规范
1、代码格式
1-对于自己编写的代码,可用官方工具gofmt,将代码格式化为同一个标准的style。
2-对于依赖包管理,官方提供工具goimports,将自动增删需要和无用的依赖包,并按依赖包的首个字母排序分类。
2、注释
注释的对象是谁?
变量;常量;函数;结构体。
注释的目的?
1-这段代码的上下文大概是什么?
2-这段代码有什么用?
3-这段代码是如何做的?
4-会发生哪些特殊或者值得注意的情况?如错误。
3、命名规范
变量命名原则?
1-简洁胜于冗长,如index int -> i int;count int -> cnt int;t time.Time -> ddl time.Time
2-变量名离使用的地方越远,则需要命名越明确,带更多上下文。但建议不要离太远。
函数名命名原则?
1-缩略词作为函数名时,需要导出就全大写,否则全小写。ServeHttp -> ServeHTTP;XMLHTTPRequest or xmlHTTPRequest;
2-因为包和函数成对出现,函数名不带包名信息。http.ServeHTTP -> httpServe;
package命名原则?
1-只有小写字母组成,不包含大写字母和下划线。
2-简短并包含一定上下文信息,做到顾名思义。如task,strings
3-不要与标准库同名,如sync,time
4-不使用常用变量名作为包名,如buf -> bufio
5-一般情况下,使用单数而不是复数,如encodings ->encoding
6-缩写要顾名思义才能缩写,如fmt -> format;ddl -> deadline
小结:一切目的都是为了扩展维护时更方便,所有需要有顾名思义的特点,没有就加上下文。
4、控制流程
1-避免if嵌套,就要善用continue,return。
2-优先处理错误,让其提前结束,从而避免嵌套。
总结:
1-避免嵌套,走逻辑直线。正常流程代码沿着屏幕向下移动,故障打多出现在复杂的嵌套中。
2-提升代码可读和可维护性。
5、错误和异常处理
1-简单错误,可能只出现一次,我们直接errors.New来创建匿名变量直接表示简单错误。如有格式化需求,可使用fmt.Errorf
2-复杂错误包装和解包Wrap、Unwrap。Wrap可一个error嵌套在另一个error中,形成一个error跟踪链。在fmt.Errorf中使用%w可将error关联中错误中。
3-在错误链上可用errors.Is来判断该链上是否含有特定错误。
4-在错误链上获取特定错误,使用errors.As
5-非普通错误panic,直接可使程序不继续工作下去。两种情况,早些暴力panic,结束程序;转panic为error,特殊处理。
6-recover机制处理panic,不能让第三方库的bug抛出的panic影响我们的自身逻辑。
3、性能优化建议
1-性能优化指标,时间效率,空间效率,但不一定是同时降,有可能是空间换时间,提高用户体验。
2-性能优化还是需要数据驱动,Go提供了支持基准测试的benchmark工具,go test -bench=. -benchmem
3-针对slice的优化--预分配容量防止频繁扩容和内容复制 || 小切片导致大数组内存无法释放。
4-针对map的优化--预分配容量防止频繁扩容、内容复制、rehash操作。
5-针对字符串的拼接处理,采用strings.Builder拼接字符串。字符串是常量,所以每次拼接都会申请新内存+内容复制。
为什么strings.Buffer比strings.Builder慢一点?
提前知道字符串大小,是否可进一步提升性能?预分配实现
6-空结构体的好处与实践--Set实现
7-性能优化之并发安全的快速实现--atomic替代加锁。
小结
1-避免常见陷阱
2-不需要一味追求程序的性能,不要破坏程序的正确可靠性。
性能调优实战
1、性能调优简介
性能调优原则?
1-数据驱动
2-定位大瓶颈热点代码,保证程序正确可靠。
3-不要过早优化,过度优化,因为产品要迭代,特别是前期可变因素很多。
2、性能分析工具pprof
pprof是一个可视化什么地方花费了多少CPU、内存的一个数据分析工具。
1、pprof 功能简介
2、pprof排查实战
1-CPU 相关
1、topN
Windows PowerShell
版权所有(C) Microsoft Corporation。保留所有权利。
安装最新的 PowerShell,了解新功能和改进!https://aka.ms/PSWindows
PS D:\Users\86158\Desktop\青训营\示例代码\go-pprof-practice> go tool pprof "http://localhost:6060/debug/pprof/profile?seconds=10"
Fetching profile over HTTP from http://localhost:6060/debug/pprof/profile?seconds=10
Saved profile in C:\Users\86158\pprof\pprof.samples.cpu.001.pb.gz
Type: cpu
Time: May 12, 2022 at 6:00pm (CST)
Duration: 10.20s, Total samples = 3.41s (33.43%)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) top
Showing nodes accounting for 3.19s, 93.55% of 3.41s total
Dropped 30 nodes (cum <= 0.02s)
Showing top 10 nodes out of 34
flat flat% sum% cum cum%
2.50s 73.31% 73.31% 2.53s 74.19% github.com/wolfogre/go-pprof-practice/animal/felidae/tiger.(*Tiger).Eat
0.38s 11.14% 84.46% 0.38s 11.14% runtime.stdcall3
0.15s 4.40% 88.86% 0.16s 4.69% runtime.stdcall6
0.03s 0.88% 89.74% 0.03s 0.88% runtime.asyncPreempt
0.03s 0.88% 90.62% 0.19s 5.57% runtime.bgscavenge
0.02s 0.59% 91.20% 0.02s 0.59% runtime.(*addrRanges).removeLast
0.02s 0.59% 91.79% 0.44s 12.90% runtime.(*pageAlloc).scavengeRangeLocked
0.02s 0.59% 92.38% 0.03s 0.88% runtime.dodeltimer0
0.02s 0.59% 92.96% 0.23s 6.74% runtime.findrunnable
0.02s 0.59% 93.55% 0.25s 7.33% runtime.schedule
(pprof)
2、list Eat
(pprof) list Eat
Total: 3.41s
ROUTINE ======================== github.com/wolfogre/go-pprof-practice/animal/canidae/dog.(*Dog).Eat in D:\Go\bin\pkg\mod\github.com\wolfogre\go-pprof-practice@v0.0.0-20190402114113-8ce266a210ee\animal\canidae\dog\dog.go
0 10ms (flat, cum) 0.29% of Total
. . 21: d.Run()
. . 22: d.Howl()
. . 23:}
. . 24:
. . 25:func (d *Dog) Eat() {
. 10ms 26: log.Println(d.Name(), "eat")
. . 27:}
. . 28:
. . 29:func (d *Dog) Drink() {
. . 30: log.Println(d.Name(), "drink")
. . 31:}
ROUTINE ======================== github.com/wolfogre/go-pprof-practice/animal/felidae/tiger.(*Tiger).Eat in D:\Go\bin\pkg\mod\github.com\wolfogre\go-pprof-practice@v0.0.0-20190402114113-8ce266a210ee\animal\felidae\tiger\tiger.go
2.50s 2.53s (flat, cum) 74.19% of Total
. . 19:}
. . 20:
. . 21:func (t *Tiger) Eat() {
. . 22: log.Println(t.Name(), "eat")
. . 23: loop := 10000000000
2.50s 2.53s 24: for i := 0; i < loop; i++ {
. . 25: // do nothing
. . 26: }
. . 27:}
. . 28:
. . 29:func (t *Tiger) Drink() {
3、web
2-Heap堆内存相关
3-goroutine相关
4-mutex-锁
5-block阻塞