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

60 阅读4分钟

高质量编程

1.编程简介

高质量:正确可靠,简洁清晰的代码

边界条件完备性

异常情况处理,是否稳定

可维护性

2.编码规范

编程原则

  1. 简单性(无冗余代码)
  2. 可读性(便于维护和交流)
  3. 生产力(团队工作效率)

代码格式

工具:

  1. gofmt官方工具,自动格式化Go语言代码位官方统一风格
  2. goimports实际等于gofmt加上依赖包管理,自动增删依赖的包引用,将依赖包按字母排序并分类

注释:

  1. 解释代码作用

  2. 解释代码如何做的

  3. 解释代码实现的原因

  4. 解释代码在什么情况会报错

小结

代码是最好的注释

注释应该提供代码未表达出的上下文信息

命名规范

变量:

  1. 尽量简洁
  2. 缩略词全大写,但在变量开头且不需要到出时,全小写 如:用 ServeHTTP 而不用 ServeHttp,用 XMLHTTPRequestxmlHTTPRequest

函数名:

  1. 尽量简短
  2. 函数名不携带包名的上下文信息,
  3. 名为foo的包某个函数返回类型Foo,可省略类型信息而防止产生歧义
  4. 名为foo的包某个函数返回类型T (T≠Foo),可在函数名中加入类型信息

包(package):

  1. 只由小写字母组成,不包含大写字母和下划线等字符
  2. 简短且包含一定的上下文信息
  3. 不要和标准库同名,防止出错

小结:

  1. 核心是降低阅读代码的成本
  2. 结合上下文代码进行参考,来命名

控制流程

  1. 避免分支嵌套,删除多余的else
  2. 尽量保持代码路径为最小缩进(观赏性,可阅读性高)

小结

  1. 线性原理,处理逻辑尽量直线,减少复杂的嵌套
  2. 可维护性和可读性
  3. bug大多出现在复杂的条件和循环语句中(找bug可侧重在逻辑语句中找)

错误和异常处理

  1. 简单错误

    errors.New // 创建匿名变量表示简单错误
    fmt.Errorf // 格式化输出
    
  2. 复杂错误

    嵌套链,可在fmt.Errorf中使用%w关键字将错误进行关联到错误链中

    errors.Is:判定错误是否为特定错误

    errors.As:在错误链上获取特定种类的错误

  3. panic

  4. 调用函数不包括recover会造成程序崩溃

  5. 如果问题可以被屏蔽或解决,建议使用error代替panic

  6. 程序启动阶段发生不可逆转的错误时,可以在initmain中使用panic

  7. recover

    1. 只能在defer中使用
    2. 嵌套中无法生效
    3. 只在当前的goroutine生效
    4. defer的语句是后进先出(队列)
    5. log中记录信息

小结:

  1. error:尽可能的提供简明的上下文信息链,方便定位问题
  2. panic:用于真正的异常
  3. recover:只在当前goroutinedefer函数中生效

3.性能优化建议

评估工具:benchmark支持基准性能测试

go test -bench=. -benchmem

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

切片:

  1. 切片本质是数组片段
    1. 包括数组指针
    2. 片段的长度
    3. 片段的容量
  2. 切片操作并不复制切片指向的元素
  3. 创建一个新的切片会复用原来切片的底层数组

大内存未释放:

  1. 在已有切片基础上创建切片,不会创建新的底层数组
    1. 原切片较大,代码在原切片基础上新建小切片
    2. 原底层数组在内存中有引用,得不到释放
  2. 可用copy代替re-slice

map预分配内存

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

字符串处理:

  1. 字符串在Go语言中是不可变类型,占用内存大小是固定的
  2. 使用+每次都会重新分配内存
  3. strings.Builder,bytes.buffer底层都是[]byte数组
  4. 内存扩容策略,不需要每次拼接都重新分配内存

空间结构体:

  1. 空结构体struct{}实例不占据任何的内存空间
  2. 可作为各场景下的占位符使用
    1. 节省资源
    2. 空结构体本身具备很强的语义,可以不赋值,仅作为占位符

使用atomic包

小结:

  1. 避免常见的性能陷阱可保证大部分的程序性能
  2. 不要一味的追求程序的性能
  3. 越高级的性能优化手段越容易出现问题
  4. 要在正确可靠,简洁清晰的前提下去提升程序性能