Go 语言上手 - 高质量编程与性能调优实战 | 青训营笔记

153 阅读4分钟

高质量编程

高质量编程简介

边界条件是否完备

异常处理稳定性

易读易维护

编程原则:简单性、可读性、生产力

编码规范

代码格式

gofmt自动格式化代码

goimports自动增删依赖的包引用

注释

  • 解释代码作用

  • 解释代码如何做的

  • 解释代码实现的原因

    • 解释代码的外部因素
    • 提供额外上下文
  • 解释代码什么情况会出错

    • 代码的限制条件

公共符号始终要注释 不需要注释实现接口的方法

代码是最好的注释

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

命名规范

  • 变量

简洁胜于冗长

缩略词全大写(如HTTP),位于变量开头且不需要导出时使用全小写

变量距离被使用的地方越远,则需要携带越多的上下文

for 循环中 index 和 i,index没有多携带信息

deadline 和 t,deadline包含特定含义的时间

  • 函数

函数名不需要携带包名类型

尽量简短

常用标准:

只用小写

简短

尽量不要做:

不要与标准库同名

不用常用变量名做包名

使用单数而不是复数

谨慎使用缩写

控制流程

避免嵌套,保持正常流程清晰

尽量保持正常路径为最小缩进

错误和异常处理

  • 简单错误

简单错误仅出现一次,且其他地方不需要捕获

优先使用errors.New("xxx") 来创建匿名变量来直接表示简单错误

需要格式化的话,可以使用fmt.Errorf

  • Wrap和Unwrap
  • 错误判定

errors.Is来判定错误链上所有错误是否含有特定的错误

errors.As可以获取特定类型的错误

  • panic

不建议在业务中使用panic

调用函数不包含recover会造成程序崩溃

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

当程序启动阶段发生不可逆转的错误时,可以在init或main中使用panic

  • recover

只能在被defer的函数中使用

嵌套无法生效

只在goroutine生效

defer后进后出

如果需要更多的上下文信息,可以在recover后在log中记录当前的调用栈

性能优化建议

如何评估代码的表现:Benchmark

  • Slice

预分配:尽可能在使用make()初始化切片时提供容量信息

缩容时:在已有切片基础上创建切片,不会创建新的底层数组,可能会导致大内存未释放,建议使用copy代替re-slice

  • Map

预分配:预分配会更好

  • strings.Builder

内存分配导致的性能差异

  • 使用空结构体

map实现set,实现占位

  • atomic包

锁的实现是操作系统实现,属于系统调用

atomic操作是通过硬件实现,效率比锁高

sync.Mutex应该用来保护一段逻辑,不仅仅用于保护一个变量

对于非数值操作,可以使用atomic.Value,能承载interface(){}

性能调优实战

性能调优简介

  • 原则

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

性能分析工具pprof实战

blog.wolfogre.com/posts/go-pp…

性能调优案例

业务优化服务

流程:

  • 建立服务性能评估手段

    • 服务性能评估方式

    • 请求流量构造

      • 不同请求参数覆盖逻辑不同
      • 线上真实流量情况
    • 压测范围

      • 单机器压测
      • 集群压测
    • 性能数据采集

      • 单机性能数据
      • 集群性能数据
    • 生成压测结果、报告

  • 分析性能数据,定位性能瓶颈

    • 使用库不规范
    • 高并发场景优化不足
  • 重点优化项改造

    • 正确性是基础

    • 响应数据diff

      • 线上请求数据录制回放
      • 新旧逻辑接口数据diff
  • 优化效果验证

    • 重复压测验证

    • 上限评估优化效果

      • 关注服务监控
      • 逐步放量
      • 收集性能数据

基础库优化

AB实验SDK优化

  • 分析基础库核心逻辑和性能瓶颈

    • 设计完善改造方案
    • 数据按需获取
    • 数据序列化协议
  • 内部压测验证

  • 推广业务服务落地验证

Go语言优化

  • 编译器&运行时优化

    • 优化内存分配策略
    • 优化代码编译流程,生成更高效的程序
    • 内部压测验证
    • 推广业务服务落地验证
  • 优点:

    • 接入简单,只需要调整编译配置
    • 通用性强