这是我参与「第五届青训营 」伴学笔记创作活动的第 3 天
Go 语言高质量编程与性能优化课堂笔记
1 本次课堂的内容
- 介绍编码规范,帮助大家写出高质量程序
- 介绍 Go 语言的性能优化建议,分析对比不同方式对性能的影响和背后的原理
- 讲解常用性能分析工具 pprof 的使用和工作原理,熟悉排查程序性能问题的基本流程
- 分析性能调优实际案例,介绍实际性能调优时的工作内容
2 详细知识点的介绍
2.1 高质量编程
编写高质量代码是程序开发中非常重要的一环,它不仅要求代码正确可靠,还要求简洁清晰,避免性能隐患。不同的语言特性和语法可能不同,但是高质量编程的原则是相通的。为了编写高质量代码,应该注重简单性、可读性和生产力等原则。
2.1.1 常见编码规范
2.1.1.1 代码格式
Go 语言使用 gofmt 自动格式化代码可以保证所有的 Go 代码与官方推荐格式保持一致
2.1.1.2 注释
注释能够帮助其他开发者和团队成员更好地理解代码的用途和实现原理。正确使用注释可以节省大量的时间和精力。
首先,注释应该解释代码的作用,这样我们就能快速了解代码的用途。其次,注释应该解释代码如何做到的。这样我们就能理解代码中使用的算法和技巧。第三,注释应该解释代码实现的原因。这样我们就能理解代码中使用的设计模式和技巧。第四,注释应该解释代码什么情况会出错。这样我们就能在遇到错误时快速定位问题。
另外,对于公共符号,如变量、常量、函数和结构体等,应该添加注释,这样我们就能更好地理解代码中的公共符号。因此,每个包中声明的公共符号都应该添加注释。
2.1.1.3 命名规范
命名规范是编写高质量代码的重要部分,它能够帮助其他开发者和团队成员更好地理解代码的用途和实现原理。正确使用命名规范可以节省大量的时间和精力。
对于变量的命名,简洁胜于冗长,缩略词全大写,但当其位于变量开头且不需要导出时,使用全小写。变量距离其被使用的地方越远,则需要携带越多的上下文信息。全局变量在其名字中需要更多的上下文信息,使得在不同地方可以轻易辨认出其含义。
对于函数的命名,函数名不携带包名的上下文信息,因为包名和函数名总是成对出现的。函数名尽量简短。当名为 foo 的包某个函数返回类型 Foo 时,可以省略类型信息而不导致歧义。当名为 foo 的包某个函数返回类型 T 时(T 并不是 Foo),可以在函数名中加入类型信息。
对于包的命名,只由小写字母组成。不包含大写字母和下划线等字符。简短并包含一定的上下文信息。例如 schema、task 等。不要与标准库同名。例如不要使用 sync 或者 strings。
通过遵循命名规范,可以使代码更易于阅读和维护,减少编码错误和提高代码可重用性。
2.1.1.4 控制流程
正确使用控制流程可以节省大量的时间和精力。为了提高代码的可读性和易维护性,我们应该避免嵌套,保持正常流程清晰,如果两个分支中都包含 return 语句,则可以去除冗余的 else。
尽量保持正常代码路径为最小缩进,优先处理错误情况/特殊情况,并尽早返回或继续循环来减少嵌套,增加可读性。这样可以使其他开发者和团队成员更好地理解代码的用途和实现原理。
2.1.1.5 错误和异常处理
错误和异常处理是非常重要的编程原则。简单错误处理应优先使用 errors. New 创建匿名变量来直接表示该错误,有格式化需求时使用 fmt. Errorf。Wrap 和 Unwrap 可以在 fmt. Errorf 中使用 %w 关键字来将一个错误 wrap 至其错误链中。使用 errors. Is 可以判定错误链上的所有错误是否含有特定的错误,使用 errors. As 可以在错误链上获取特定种类的错误。
在业务代码中不建议使用 panic,如果当前 goroutine 中所有 deferred 函数都不包含 recover 就会造成整个程序崩溃。当程序启动阶段发生不可逆转的错误时,可以在 init 或 main 函数中使用 panic。recover 只能在被 defer 的函数中使用,嵌套无法生效,只在当前 goroutine 生效。如果需要更多的上下文信息,可以 recover 后在 log 中记录当前的调用栈。
3 实践练习例子
使用 pprof 工具对性能进行分析,可以知道应用在什么地方耗费了多少 CPU、memory 等运行指标
4 总结
在这节课中,我学习了编写程序时遵循的编码规范的重要性,学会了如何编写出高质量的代码。此外,我还学习了 Go 语言中常见的性能优化技巧,并学会了分析不同优化方法对性能的影响及其背后的原理。我还学习了使用常用的性能分析工具 pprof,了解了如何排查程序性能问题的基本流程。最后,我还通过实际案例分析了性能调优的过程,了解了实际性能调优工作中的内容。