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

73 阅读5分钟

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

一、本堂课重点内容:

1. 高质量编程

2. 性能调优

  • 性能调优简介
  • 性能分析工具 pprof 实战
  • 性能调优案例

二、详细知识点介绍:

1. 高质量编程

  • 高质量编程简介
    • 简单性:不要瞎拽技术,能用简单的就不要用复杂的
    • 可读性:代码在机器眼中就是0和1,规范的目的是给人看的
    • 生产力:效率是第一位
  • 编码规范
    • 代码格式
      gofmt自动格式代码

    • 注释
      1.解释代码的作用
      2.如何做的
      3.实现的原因
      4.什么时候会出错

    • 命名规范
      命名是代码规范中很重要的一部分,统一的命名规则有利于提高的代码的可读性,好的命名仅仅通过命名就可以获取到足够多的信息。
      1. 包命名:package
      保持package的名字和目录保持一致,尽量采取有意义的包名,简短,有意义,尽量和标准库不要冲突。包名应该为小写单词,不要使用下划线或者混合大小写。

      package demo
          
      package main
      

      2. 文件命名 尽量采取有意义的文件名,简短,有意义,应该为小写单词,使用下划线分隔各个单词。

      my_test.go
      

      3. 结构体命名

      • 采用驼峰命名法,首字母根据访问控制大写或者小写
      • struct 申明和初始化格式采用多行,例如下面:
      // 多行申明
      type User struct{
          Username  string
          Email     string
      }
      // 多行初始化
      u := User{
          Username: "Nbetray",
          Email:    "Nbetray@qq.com",
      }
      

      4. 接口命名

      • 命名规则基本和上面的结构体类型
      • 单个函数的结构名以 “er” 作为后缀,例如 Reader , Writer 。
      type Reader interface {
              Read(p []byte) (n int, err error)
      }
      

      5. 变量命名

      • 和结构体类似,变量名称一般遵循驼峰法,首字母根据访问控制原则大写或者小写,但遇到特有名词时,需要遵循以下规则:
      • 如果变量为私有,且特有名词为首个单词,则使用小写,如 apiClient
      • 其它情况都应当使用该名词原有的写法,如 APIClient、repoID、UserID
      • 错误示例:UrlArray,应该写成 urlArray 或者 URLArray
      • 若变量类型为 bool 类型,则名称应以 Has, Is, Can 或 Allow 开头
      var isExist bool
      var hasConflict bool
      var canManage bool
      var allowGitHook bool
      

      6. 常量命名
      常量均需使用全部大写字母组成,并使用下划线分词

      const APP_VER = "1.0"
      

      如果是枚举类型的常量,需要先创建相应类型:

      type Scheme string
      const (
          HTTP  Scheme = "http"
          HTTPS Scheme = "https"
      )
      

      7. 关键字
      保留字不能用作常量或变量或任何其他标识符名称。

    • 控制流程
      1.线性原理,处理逻辑尽量走直线,避免复杂的嵌套分支
      2.正常流程代码沿着屏幕向下移动
      3.提升代码可维护性和可读性
      4.故障问题大多出现在复杂的条件语句和循环语句中

    • 错误和异常处理
      1.error尽可能提供简明的上下文信息链,方便定位问题
      2.panic 用于真正异常的情况
      3.recover生效范围,在当前 goroutine 的被 defer 的函数中生效

  • 性能优化建议
    • 简介

      • 性能优化的前提是满足正确可靠、简洁清晰等质量因素
      • 性能优化是综合评估,有时候时间效率和空间效率可能对立
      • 避免常见的性能可以保证大部分程序的性能
      • 普通应用代码,不要一味地追求程序的性能
      • 越高级的性能优化手段越容易出现问题
      • 在满足正确可靠、简洁清晰的质量要求的前提下提高程序性能
    • Benchmark

      • 能表现需要实际数据衡量
      • Go语言提供了支持基准性能测试的benchmark工具
    • Slice

      • slice预分配内存:尽可能在使用make()初始化切片时提供容量信息
      • 大内存未释放:
        • 在已有切片基础上创建切片,不会创建新的底层数组
        • 场景:
          原切片较大,代码在原切片基础上新建小切片
          原底层数组在内存中有引用,得不到释放
        • 可使用copy替代re-slice
    • Map

      • 预分配内存:建议根据实际需求提前预估好需要的空间
    • 字符串处理

      • 使用 + 拼接性能最差,strings.Builder与bytes.Buffer相近,但strings.Buffer更快
    • 空结构体

      • 占位符,省内存
    • atomic包

      • 使用
      //使用atomic包
      type atomiccounter struct {
          i int32
      }
      func AtomicAddone (c *atomiccounter) {
          atomic.Addint32(&c.i,1)
      }
      
      //不使用atomic包
      type mutexcounter struct {
          i int32
          m Sync.Mutex
      }
      func MutexAddone (c *mutexCounter) {
          c.m.Lock()
          c.i++
          c.m.Unlock()
      }
      

      对比 image.png

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

2. 性能调优

  • 性能调优简介

三、实践练习例子:

  • 性能分析工具 pprof 实战
  • 性能调优案例

四、课后个人总结:

  • 需掌握良好的编程规范
  • 学会分析代码性能,并且逐步调优

五、引用参考:

1.‌高质量编程与性能调优实战