Go高质量编程简介及性能调优 | 青训营笔记

97 阅读5分钟

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

目录

  1. 高质量编程

    • 高质量编程简介
    • 编码规范
    • 性能优化及建议
  2. 性能调优实战

    • 性能调优简介
    • 性能分析工具 pprof 实战

1.高质量编程

高质量编程简介

高质量的代码一般来说具备这几个特点:正确可靠、简洁清晰、高效可读

  • 程序的正确可靠性表现在对于各种边界条件是否考虑完全
  • 对于异常情况是否进行了处理
  • 代码是否易于维护

编码规范

  • 代码格式
  • 注释
  • 命名规范
  • 控制流程
  • 错误和异常处理

代码格式
推荐使用gofmt 自动格式化代码, gofmt 是Go官方提供的工具,能自动在你保存后为Go语言代码统一为官方风格 在项目中使用 gofmt 非常简单,只需要在控制台输入如下命令:

go get golang.org/x/tools/cmd/goimports

注释
对于函数注释,我们应该统一注释在函数上方,便于IDE进行解析,让我们不需要进行跳转也可以看到注释的内容。同时注释的内容应该精炼,说明功能与大概的执行逻辑。
代码其实就是最好的注释:如果代码表达的内容已经足够清晰,那么注释也应该相应少一些。

命名规范

变量名:简洁,缩略词全大写,准确表达变量的意义

//一个好的演示
func (c *Clinet) send(req *Request, deadline time.Time)
// 使用t命名后我们就不知道这里的t变量是拿来做什么的了
func (c *Clinet) send(req *Request, t time.Time)

包名:只由小写字母组成,不包含其他字符,不与标准库同名
函数名:简洁易读,能表达函数的功能

控制流程

  • 保持最小缩进(能4个空格就不要使用8个空格)
  • 处理的逻辑尽量为直线,避免过度复杂的嵌套
  • 正常的流程代码应该沿着屏幕向下移动

错误和异常处理

简单错误

  • 简单错误是指仅仅出现一次的错误,且其他的地方不需要捕获该错误
  • 优先使用errors.New 来创建匿名变量来直接表示简单错误
  • 需要格式化错误信息则可以使用 fmt.Errorf
func div(a int, b int) {
    if b == 0 {
        errors.New("div by zero")
    }
    return a / b
}
  • Wrap与Unnwrap
err1 := errors.New("new error")
err2 := fmt.Errorf("err2: [%w]", err1)
err3 := fmt.Errorf("err3: [%w]", err2)

fmt.Println(errors.Unwrap(err3))
fmt.Println(errors.Unwrap(errors.Unwrap(err3)))
// output
err2: [new error]
new error

错误判定

errors.ls 和 errors.As
当错误被多层包装后,我们如何在调用链上游判断其是否为底层中的一个错误呢?
使用errors.ls,它递归调用 Unwrap 并判断每一层的 err 并进行判断,如果有任何一层 err 和传入的目标错误(target)相等,则返回 true。

err1 := errors.New("new error")
err2 := fmt.Errorf("err2: [%w]", err1)
err3 := fmt.Errorf("err3: [%w]", err2)

fmt.Println(errors.Is(err3, err2))
fmt.Println(errors.Is(err3, err1))
// output
true
true

panic 和 recover
panic对于程序来说是出现了毁灭性的错误,比如内存泄露等等(此时我们无法继续运行程序,只能被迫中断)
所以在业务代码中对于异常的处理是很少使用panic的,这会极大的降低用户对我们程序的使用体验感。
大多数可以挽救的错误我们一般是使用recover来进行处理,让程序回到正常的流程当中继续运行。
具体的使用可以见:【Go基础】panic & recover - 掘金 (juejin.cn)

2.性能调优实战

性能调优简介

原则

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

性能分析工具 pprof 实战

pprof 是 Go 语言中分析程序运行性能的工具,它能提供各种性能数据:

  • allocs: 内存分配情况
  • blocks: 阻塞操作情况
  • cmdline: 显示程序启动命令及参数
  • goroutine: 显示当前所有线程的堆栈信息
  • heap:堆上内存的使用信息
  • mutex:锁的使用情况
  • profile: cpu占用的情况
  • threadcreat:系统线程创建的信息
  • trace: 程序运行跟踪信息

image.png

先将pprof练习项目下载到本地

git clone https://github.com/google/pprof

运行:

image.png 可以看到内存占用瞬间就高起来了。接下来我们将使用pprof工具定位到代码中导致内存占用飙高的代码,并进行优化或删除。

控制台输入:

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

image.png

image.png 可以看到Eat这个方法导致了大部分的内存占用
使用 list 正则表达式 输出具体函数的代码

list Eat

image.png

不过控制台使用不方便去进行查看,我们可以使用web命令(这步需要在cmd或powershell下输入,出现错误往下看),打开浏览器,使用图形化界面进行查看

image.png

tips:如果你在使用web命令时出现了如下错误:

failed to execute dot. Is Graphviz installed? Error: exec: "dot": executable file not found in %PATH%

首先idea内置的控制台界面好像是没法使用这个命令的(等待验证
其次就是说明你的电脑缺少GraphvizDownload | Graphviz 安装完成后,记得将Graphviz的bin目录添加到环境变量PATH中

一切完成后就可以了。 同时,我们还可以使用更好用的UI界面
tips:URL最后一个参数就是我们需要查看的性能指标了(这里我们查看heap的使用情况)

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

访问:http://localhost:8080/

image.png

最后我们通过分析,找到了引起内存飙高的代码处并进行了优化。