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

53 阅读3分钟

day03-高质量编程与性能调优

  1. 原则

    1. 简单性

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

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

    1. 可读性

    • 代码是写给人看的,而不是机器

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

    1. 生产力

    • 团队整体工作效率非常重要
  2. 编码规范

    1. 推荐使用gofmt自动格式化

    2. 注释

    • 解释代码作用

    • 解释代码如何做的

    • 解释代码实现的原因

    • 解释代码什么情况会出错

    1. 命名规范

    • 缩略词全大写
    • function
    • package
  3. Go性能优化

    1. slice预分配内存

slice.png 为slice预分配内存,与slice原理有关 * 切片本质是一个数组片段的描述 * 包括数组指针 * 片段的长度 * 片段的容量(不改变内存分配情况下的最大长度) * 切片操作并不复制切片指向的元素 * 创建一个新的切片会复用原来的切片的底层数组 大内存未释放 * 在已有切片的基础上创建切片,不会创建新的底层数组 * 场景 * 原切片较大,代码在原切片的基础上新建小切片 * 原底层数组在内存中有引用,得不到释放 * 可用copy代替re-slice 2. map预分配内存 * 不断向map中添加元素的操作会触发map的扩容 * 提前分配好空间可以减少内存拷贝和Rehash的扩容 * 根据实际需求提前预估好需要的时间 3. 字符串处理

**使用strings.Builder**,使用`+`拼接性能最差,`strings.Builder``bytes.Buffer`相近,`strings.Buffer`更快

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

4.  空结构体
    **使用空结构体节省内存**,空结构体`struct{}`不占据任何内存空间,仅作为占位符

*   实现`Set`,可以考虑用`map`来代替
*   对于这个场景,只需要用到`map`的键,而不需要值
*   即使是将map的值设置为bool类型,也会多占据1个字节空间

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

4. 性能分析工具pprof pprof.png go tools pprof "url/debug/pprof/profile?seconds=xxx" 1. CPU 使用top命令查看看占用资源最多的函数 * flat 当前函数本身的执行耗时

*   `flat%` flat占CPU总时间的比例

*   `sum%` 上面每一行的flat%总和

*   `cum` 指当前函数本身加上其调用函数的总耗时

*   `cum%` cum占CPU总时间的比例
    当`flat == cum`,函数中没有调用其他函数,`flat == 0`函数中只有其他函数的调用
    `web`命令可以查看调用关系可视化
2.  Heap-堆内存

go tools pprof -http=:8080 "url/debug/pprof/heap"c 访问url:8080/ui即可查看heap

  1. goroutine-协程

go tools pprof -http=:8080 "url/debug/pprof/goroutine"

火焰图

  • 由上到下表示调用顺序
  • 小方块代表函数 方块越长函数占用CPU时间越多
  1. mutex-锁 go tools pprof -http=:8080 "url/debug/pprof/mutex"

  2. block-阻塞 go tools pprof -http=:8080 "url/debug/pprof/block"