Go笔记3|青训营

66 阅读5分钟

高质量编程

代码正确可靠、简洁清晰

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

编程原则

简单性

  • 消除“多余的复杂性”,以简单清晰的逻辑编写代码
  • 不理解的代码无法修复改进

可读性

  • 代码是写给人看的,而不是机器
  • 编写可维护代码的第一步是确保代码可读

生产力

  • 团队整体工作效率非常重要

编码规范

代码格式

使用gofmt/goimports

注释

  • 注释应该做的
    • 解释代码作用
    • 解释代码如何做的
    • 解释代码实现的原因
      • 适合解释代码的外部因素
    • 解释代码什么情况会出错
  • 公共符号始终要注释
    • 包中声明的每个公共的符号:变量、常量、函数以及结构都需要添加注释
    • 任何既不明显也不简短的公共功能必须予以注释
    • 无论长度或复杂程度如何,对库中的任何函数都必须进行注释
  • 接口不用注释

命名规范

  • 变量
    • 简洁胜于冗长
    • 缩略词全大写,但当其位于变量开头且不需要导出时,使用全小写
      • 例如使用ServeHTTP而不是ServeHttp
      • 使用XMLHTTPRequest或者xmlHTTPRequest
    • 变量距离其被使用的地方越远,则需要携带越多的上下文信息
      • 全局变量在其名字中需要更多的上下文信息,使得在不同地方可以轻易辨认出其含义
  • 函数
    • 函数名不携带包名的上下文信息,因为包名和函数名总是成对出现的
    • 函数名尽量简短
    • 当名为foo的包某个函数返回类型Foo时,可以省略类型信息而不导致歧义
    • 当名为foo的包某个函数返回类型T时(T并不是Foo),可以在函数名中加入类型信息
    • 只由小写字母组成。不包含大写字母和下划线等字符
    • 简短并包含一定的上下文信息。例如schema、task等
    • 不要与标准库同名。例如不要使用sync或者strings
    • 不使用常用变量名作为包名。例如使用bufio而不是buf
    • 使用单数而不是复数。例如使用encoding而不是encodings
    • 谨慎地使用缩写。例如使用fmt在不破坏上下文的情况下比format更加简短
  • 控制流程
    • 避免嵌套,保持正常流程清晰 如果两个分支中都包含return语句,则可以去除冗余的else

    • 尽量保持正常代码路径为最小缩进 优先处理错误情况/特殊情况,尽早返回或继续循环来减少嵌套

  • 错误和异常处理
    • 简单错误
      • 简单的错误指的是仅出现一次的错误,且在其他地方不需要捕获该错误
      • 优先使用errors.New来创建匿名变量来直接表示简单错误
      • 如果有格式化的需求,使用fmt.Errorf
    • 复杂错误
      • 错误的Wrap实际上是提供了一个error嵌套另一个eror的能力,从而生成一个error的跟踪链
      • 在fmt.Errorf中使用:%w关键字来将一个错误关联至错误链中
    • 错误判定
      • 判定一个错误是否为特定错误,使用errors.ls 不同于使用==,使用该方法可以判定错误链上的所有错误是否含有特定的错误

      • 在错误链上获取特定种类的错误,使用errors.As

    • panic
      • 不建议在业务代码中使用panic
      • 调用函数不包含recover会造成程序崩溃若问题可以被屏蔽或解决,建议使用eror代替panic
      • 当程序启动阶段发生不可逆转的错误时,可以在init或main函数中使用panic
    • recover
      • recover只能在被defer的函数中使用
      • 嵌套无法生效
      • 只在当前goroutine生效
      • defer的语句是后进先出
      • 用来记录调用栈

性能优化建议

Benchmark

  • 评估性能

Slice切片

  • 预分配内存
  • 在已有切片上创建新的切片,会导致原底层数组在内存中有引用,得不到释放,可用copy替代

Map

  • 预分配内存

字符串

  • 使用+拼接性能最,strings.Builder,bytes.Buffer相近,strings.Builder更快
  • 拼接时用Grow预分配内存

空结构体

  • 不占内存,可做占位符

atomic包

  • 实现加锁,保护变量,比Mutex快

性能调优

原则

  • 要依靠数据不是猜测
  • 要定位最大瓶颈而不是细枝末节
  • 不要过早优化
  • 不要过度优化

工具pprof

可视化和分析性能分析数据的工具

命令

  • topN 查看占用资源最多的函数
    • flat——当前函数本身的执行耗时
    • flat%—— flat 占 CPU 总时间的比例
    • sum%——上面每一行的 flat% 总和
    • cum——指当前函数本身加上其调用函数的总耗时
    • cum%—— cum 占 CPU 总时间的比例
  • list 根据指定的正则表达式查找代码行
  • web 关系可视化
  • heap 堆内存
  • goroutine 协程
  • mutex 锁
  • block 阻塞

实际

业务服务优化

  • 服务:能单独部署,承载一定功能的程序
  • 依赖:Service A的功能实现依赖Service B的响应结果,称为Service A依赖Service B
  • 调用链路:能支持一个接口请求的相关服务集合及其相互之间的依赖关系
  • 基础库:公共的工具包、中间件
  • 建立服务性能评估手段
    • 服务性能评估方式
      • 单独benchmark无法满足复杂逻辑分析
      • 不同负载情况下性能表现差异
    • 请求流量构造
      • 不同请求参数覆盖逻辑不同
      • 线上真实流量情况
    • 压测范围
      • 单机器压测
      • 集群压测
    • 性能数据采集
      • 单机性能数据
      • 集群性能数据