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

58 阅读4分钟

1.高质量编程

什么是质量

  • 各种边界条件是否考虑完备
  • 异常情况处理,稳定性保证
  • 易读易维护

编程原则

  • 简单性
  • 可读性
  • 生产力

编程规范

  • 代码格式

    • 推荐使用gofmt自动格式化代码
  • 注释

    • 解释代码作用 (注释公共符号(变量、函数))
    • 解释代码是如何做的 (解释实现过程)
    • 解释代码实现的原因(解释外界因素)
    • 解释代码在什么情况下可能会出错(解释限制条件)
  • 命名规范

    • variable

      • 简洁胜于冗长
      • 缩略词全大写
      • 变量距离被使用的距离越远,名字应该携带更多的上下文信息
    • function

      • 不携带包名信息,因为总是成对出现的
      • 函数名尽量简短
      • 当foo包中的某个函数返回类型Foo时,可以省略信息而不导致歧义
      • 当foo包中的某个函数返回类型T(T不是Foo)时,可以在函数名中加入类型信息
    • package

      • 只由小写字母组成,不包括大写字母和下划线

      • 简短并包含一定的上下文信息

      • 不要与标准库同名

        • 不使用变量名作为包名
        • 使用单数而不是复数
        • 谨慎使用缩写
  • 流程控制

    • 避免嵌套
    • 尽量保持正常代码路径为最小缩进(优先处理错误和特殊情况,不让正常情况嵌套很深)
    • 正常流程沿着屏幕向下移动
    • 故障问题通常出在复杂的条件语句和循环之中
  • 错误和异常处理

    • 简单错误

      • 仅出现一次的错误
      • 优先使用errors.New()来创建匿名错误类型
      • 如果有格式化的需求,使用fmt.Errorf
    • 错误的Wrap和Unwrap

      • 错误的wrap其实就是一个错误包装了另一个错误
      • 在fmt.Errorf中使用:%w关键字关联至错误链中
    • 错误判定

      • 判断是否是错误 errors.Is()
      • 判断错误分类 errors.As()
    • panic

      • 不建议在业务代码中使用panic
      • 如果函数中不包含recover会引起程序崩溃
      • 如果错误可以屏蔽或者解决,尽量使用error
    • recover

      • recover只能在defer中使用
      • 只在当前goroutine中生效
      • defer语句是先进后出

2.性能优化

指南

在满足正确可靠、简洁清晰的质量要求的前提下提高程序性能

  • Slice

    • 内存预分配 尽可能在make的时候提供容量信息
    • 建议用copy替代slice[m:n],因为如果只取了slice里面的很小一部分,但是其他部分不会被回收,就造成了很大的内存浪费,copy一部分走,大的切片就有机会被回收
  • map

    • 内存预分配 提前分配好空间会减少内存拷贝和Rehash的消耗
  • strings.Builder

    • 使用这样一个方式拼接字符串可以有效提升性能
    • 如果预知长度,也可以提前分配容量,提升性能
  • 空结构体

    • 空结构体struct{}不占用任何内存

    • 在各个场景下的占位符使用

      • 节省资源
      • 不需要任何值,仅作为占位符 比如 map[string]struct{}
    • 实现Set(即使是设置为bool类型, 也会占用一个字节的空间)

  • atomic包

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

原则

要依靠数据而不是猜测

要定位最大瓶颈而不是细枝末节

不要过早优化

不要过度优化

工具 pprof

  • 希望知晓应用在什么地方耗费了多少CPU,Memory
  • pprof

克隆一个pprof-practice项目 github.com/wolfogre/go… 并运行

打开http://localhost:6060/debug/pprof/看到如下界面

image.png

可以点击查看详细信息

image.png

可以在终端上查看更友好的信息

go tool pprof "http://localhost:6060/debug/pprof/profile?seconds=10" 监控十秒,进入pprof控制台

输入top命令,得到以下结果

image.png

flat是当前函数调用的时间,cum是当前函数包括了所调用函数的运行时间 (flat=cum说明没有调用其他函数,flat=0说明只调用了其他函数)

看到tiger.Eat方法耗时较多,输入命令 list Eat

image.png

可以看到是在一个for循环中耗时明显,即可以找到问题所在

image.png

定位问题之后,就可以对其进行优化