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

93 阅读5分钟

目的

  • 如何编写更简洁清晰的代码
  • 常用GO语言程序优化手段
  • 熟悉GO程序性能分析工具
  • 了解工程中性能优化的原则和流程

01.高质量编程

1.1高质量编程简介

正确可靠(边界条件考虑完备,用户输入异常情况处理稳定性保证,预期之外)、简洁清晰的目标(团队易读,易维护,迭代优化) 高质量编程原则:

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

不理解的代码无法修复改进

  • 可读性 写给人看的,不是及其

编写可维护代码的第一步是确保代码可读

  • 生产力 团队整体工作效率非常重要

1.2编码规范

如何编写高质量的GO代码

代码格式

使用gofmt 自动格式化代码

goimports 对依赖包管理

注释

解释代码作用、代码如何做的、代码实现的原因、锁门情况会出错、公告符号

命名规范

  • 简洁胜于冗长
  • 缩略词全大写,但当其位于变量开头且不需要导出时候,使用全小写
    • eg:ServeHTTP,而不是ServeHttp
    • eg:XMLHTTPRequest or xmlHTTPRequest
  • 变量距离其被使用的地方越远,则需携带越多的上下文信息
    • 全局变量在其名字中需要更多的上下文信息,使得在不同地方可以轻易辨认出其含义

image.png 在这种情况下用字符较短的i比index适合

image.png 需要向外传值的时候

image.png 选一,理由:包名

image.png

小结

  • 核心目标是降低阅读代码的成不
  • 重点考虑上下文信息,设计简洁清晰的名称

控制流程

避免嵌套,保持正常流程清晰 image.png 尽量保持正常代码路径位最小缩进 优先处理错误情况/特殊情况,尽早返回或继续循环来减少嵌套

image.png

image.png

image.png

错误和异常处理

简单错误

  • 简单的错误指的是仅出现一次的错误,且在其他地方不需要捕获该错误
  • 优先使用errors.New 来创建变量直接表示简单错误
  • 如果有格式化的需求,使用fmt.Errorf image.png

错误的Wrap 和Unwrap

image.png

错误判定

  • 判定一个错误是否位特定错误,是同errors.Is
  • 不同于使用 == ,使用该方法可以判定错误链上的所有错误是否含有特定的错误

image.png

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

image.png

panic 的出现,表示程序无法正常工作了

  • 不建议在业务代码中使用panic
  • 调用函数不包含recover 会造成程序崩溃
  • 若问题可以被屏蔽或解决,建议使用error 代替panic
  • 当层析液启动阶段发生不可逆转的错误时,可以在init 或 main函数中使用panic 尽早暴露 image.png

recover

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

image.png

小结

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)
   }
}

image.png BenchmarkFib0是测试函数名

-8表示GOMAXPROCS的值为8(cpu核数)

表示一共执行了 2459036 次,即b.N的值

每次执行花费 647.8ns

性能优化建议——Slice 切片

slice 预分配内存 尽可能在使用make()初始化切片时提供容量信息

image.png

image.png

image.png

性能优化建议——Map

make 时预分配

image.png

map 预分配内存 分析

  • 不断向 map 中添加元素的操作会触发map 的扩容
  • 提前分配好空间可以减少内存拷贝和 Rehash 的消耗
  • 建议根据实际需求提前预估好需要的空间

字符串处理 使用strings.Builder 会较好 直接将底层的[]byte 转换成了字符串类型返回

image.png

性能优化建议-空结构体

image.png

image.png

性能优化建议-atomic 包

多线程编程

image.png atomic 包会比加锁性能好很多

使用 atomic 包

  • 锁的实现是通过操作系统来实现,属于系统调用
  • atomic 操作是通过硬件实现,效率比锁高
  • sync.Mutex 应该用来保护一段逻辑,不仅仅用于保护应该变量
  • 对于非数值操作,可以使用atomic.Value,能承载应该 interface{}

小结

  • 避免常见的性能陷阱可以保证大部分程序的性能
  • 普通应用代码,不要一味追求程序的性能
  • 越高级的性能优化手段越容易出现问题
  • 在满足正确可靠、简洁清晰的质量要求的前提下提高程序性能

02.性能调优实战

2.1性能调优简介

性能调优原则

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

2.2性能分析工具pprof实战

说明

希望知道应用在什么地方消费了多少CPU、Memory

pprof 是用于可视化和性能分析数据的工具

功能简介

image.png

github.com/wolfogre/go… 实战案例

性能调优案例