高质量编程与性能优化 | 青训营笔记

52 阅读2分钟

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

一、本堂课重点内容:

  • 高质量编程
  • 性能调优

二、详细知识点介绍:

1.高质量编程

1.1高质量的要求:

  • 各种边界条件是否考虑完备
  • 异常情况处理
  • 易读易维护

1.2知识点:

1.2.1写高质量GO代码
  • 代码格式

    • gofmt
  • 注释

    • 公共符号始终要注释

    • 注释内容

      1. 代码作用
      2. 代码如何做的(例:实现过程)
      3. 代码实现原因
      4. 代码什么情况下会出错(例:限制条件)
  • 命名规范

    • 变量名

      1. 缩略词全大写
      2. 变量距离被使用的地方越远,则需要携带越多上下文信息(例:全局变量)
    • 函数名

      1. 不携带包名

        例如:http包中func Serve()func ServeHTTP()更规范

      2. 返回类型与函数名一致可省略类型信息

    • package

      1. 只用小写字母
      2. 不与标准库同名
  • 控制流程

    • 避免嵌套
    • 优先处理错误/特殊情况,尽早返回或继续循环来减少嵌套
  • 错误和异常处理

    • 优先使用errors.New来创建匿名变量直接表示简单错误
    • 如果有格式化需求,使用fmt.Errorf
    • Wrap:提供一个error嵌套另一个error的能力,从而生成error跟踪连
    • fmt.Errorf中使用%w:将一个错误关联至错误链中
    • errors.Is:类似于==,用来判断是否为特定错误
    • errors.As:在错误链上获取特定种类的错误
    • panic:用于真正异常的情况
    • recover:在当前goroutine的被defer的函数中生效

2.性能调试

2.1 benchmark

go test -bench=. -benchmem

2.2 Slice

  • 尽量在make()初始化时提供容量信息
type slice struct{
array unsafe.Pointer
len int
cap int
}

由于创建新切片时会复用原来切片的底层数组->大内存未释放

  • 建议用copy代替重新创建切片

    • 可用go test -run=. -v测试

2.3 map

建议根据实际需求提前预估所需空间

原因:

  1. 向map添加元素会触发map扩容
  2. 提前分配可减少内存拷贝和rehash的消耗

2.4字符串处理

  • 拼接字符串:

    • strings.Buider 性能最好
    • bytes.Bufffer
    • +号拼接
  • 原因:

    • 字符串是不可变类型,内存固定
    • 使用+每次会重新分配内存
    • bytes.Buffferstrings.Buider 底层都是[]byte数组
  • 预分配:

    //对于strings.Buider
    var builder strings.Builder
    //预分配
    builder.Grow(n*len(str))
    //对于bytes.Bufffer
    buf:=new(bytes.Buffer)
    //预分配
    buf.Grow(n*len(str))
    ​
    

2.5 空结构体

适用于实现set,可以考虑用map空结构体替代,对于只用map键,不用值的场景

2.6 atomic包

对比于加锁操作性能更好

原因:锁实现通过操作系统,属于系统调用,atomic操作用过硬件

注意:

  1. sync.Mutex应该原来保护一段逻辑,不仅用于保护变量
  2. 非数值操作可以用atomic.Value,能承载interface{}