目的
- 如何编写更简洁清晰的代码
- 常用GO语言程序优化手段
- 熟悉GO程序性能分析工具
- 了解工程中性能优化的原则和流程
01.高质量编程
1.1高质量编程简介
正确可靠(边界条件考虑完备,用户输入异常情况处理稳定性保证,预期之外)、简洁清晰的目标(团队易读,易维护,迭代优化) 高质量编程原则:
- 简单性 消除“多余的复杂性”,以简单清晰的逻辑编写代码
不理解的代码无法修复改进
- 可读性 写给人看的,不是及其
编写可维护代码的第一步是确保代码可读
- 生产力 团队整体工作效率非常重要
1.2编码规范
如何编写高质量的GO代码
代码格式
使用gofmt 自动格式化代码
goimports 对依赖包管理
注释
解释代码作用、代码如何做的、代码实现的原因、锁门情况会出错、公告符号
命名规范
- 简洁胜于冗长
- 缩略词全大写,但当其位于变量开头且不需要导出时候,使用全小写
- eg:ServeHTTP,而不是ServeHttp
- eg:XMLHTTPRequest or xmlHTTPRequest
- 变量距离其被使用的地方越远,则需携带越多的上下文信息
- 全局变量在其名字中需要更多的上下文信息,使得在不同地方可以轻易辨认出其含义
在这种情况下用字符较短的i比index适合
需要向外传值的时候
选一,理由:包名
小结
- 核心目标是降低阅读代码的成不
- 重点考虑上下文信息,设计简洁清晰的名称
控制流程
避免嵌套,保持正常流程清晰
尽量保持正常代码路径位最小缩进 优先处理错误情况/特殊情况,尽早返回或继续循环来减少嵌套
错误和异常处理
简单错误
- 简单的错误指的是仅出现一次的错误,且在其他地方不需要捕获该错误
- 优先使用errors.New 来创建变量直接表示简单错误
- 如果有格式化的需求,使用fmt.Errorf
错误的Wrap 和Unwrap
错误判定
- 判定一个错误是否位特定错误,是同errors.Is
- 不同于使用 == ,使用该方法可以判定错误链上的所有错误是否含有特定的错误
- 在错误链上获取特定类的错误,使用errors.As
panic 的出现,表示程序无法正常工作了
- 不建议在业务代码中使用panic
- 调用函数不包含recover 会造成程序崩溃
- 若问题可以被屏蔽或解决,建议使用error 代替panic
- 当层析液启动阶段发生不可逆转的错误时,可以在init 或 main函数中使用panic
尽早暴露
recover
- 如果需要更多的上下文信息,可以recover后在log中记录当前的调用栈
小结
error 尽可能提供简明的上下文信息链,方便定位问题 panic 用于真正异常的情况 recover 生效范围,在当前 goroutine 的被defer 的函数中生效
1.3性能优化建议
性能优化的前提是满足正确可靠、简洁清晰等因素 性能优化是综合评估,有时候时间效率和空间效率可能对立 针对Go语言特性,介绍Go相关的性能优化建议
性能优化建议——Benchmark
如何使用
- 性能表现需要实际数据衡量
- Go语言提供了支持基准性能测试的benchmark工具
go test -bench=. -benchmem
//from fib.go
func Fib(n int) int {
if n < 2 {
return n
}
return Fib(n-1) + Fib(n-2)
}
//from fib_test.go
import (
"testing"
)
func BenchmarkFib0(b *testing.B) {
for n := 0; n < b.N; n++ {
Fib(10)
}
}
BenchmarkFib0是测试函数名
-8表示GOMAXPROCS的值为8(cpu核数)
表示一共执行了 2459036 次,即b.N的值
每次执行花费 647.8ns
性能优化建议——Slice 切片
slice 预分配内存 尽可能在使用make()初始化切片时提供容量信息
性能优化建议——Map
make 时预分配
map 预分配内存 分析
- 不断向 map 中添加元素的操作会触发map 的扩容
- 提前分配好空间可以减少内存拷贝和 Rehash 的消耗
- 建议根据实际需求提前预估好需要的空间
字符串处理 使用strings.Builder 会较好 直接将底层的[]byte 转换成了字符串类型返回
性能优化建议-空结构体
性能优化建议-atomic 包
多线程编程
atomic 包会比加锁性能好很多
使用 atomic 包
- 锁的实现是通过操作系统来实现,属于系统调用
- atomic 操作是通过硬件实现,效率比锁高
- sync.Mutex 应该用来保护一段逻辑,不仅仅用于保护应该变量
- 对于非数值操作,可以使用atomic.Value,能承载应该 interface{}
小结
- 避免常见的性能陷阱可以保证大部分程序的性能
- 普通应用代码,不要一味追求程序的性能
- 越高级的性能优化手段越容易出现问题
- 在满足正确可靠、简洁清晰的质量要求的前提下提高程序性能
02.性能调优实战
2.1性能调优简介
性能调优原则
- 要依靠数据不是猜测
- 要定位最大瓶颈而不是细枝末节
- 不要过早优化
- 不要过度优化
2.2性能分析工具pprof实战
说明
希望知道应用在什么地方消费了多少CPU、Memory
pprof 是用于可视化和性能分析数据的工具
功能简介