Go语言快速上手(三) | 青训营笔记

107 阅读4分钟

这是我参与第三届青训营-后端场笔记创作活动的第三篇笔记

编写高质量代码的规则

编程原则: 简单性(尽可能以简单清晰的逻辑编写代码), 可读性(更容易读懂的代码), 生产力(可以通过工具检验代码, 排除错误, 为项目进度提速)

编写高质量的Go代码: 代码格式, 注释, 命名规范, 控制流程, 错误和异常处理

注释应该写什么:

  • 代码的作用 [函数的内容]
  • 代码如何做 [解释某部分代码的实现原因]
  • 代码如何实现的(即实现的原因) [解释某一行脱离上下文的代码, 解释其外部因素以及提供额外的上下文]
  • 代码可能出错的情况 [运用场景, 解释代码的限制条件]
  • 解释: 返回值
  • 对于公共(public)提供的函数, 变量, 常量, 结构都得有注释

接口无需注释实现方法

命名规范:

  • 简短明了
  • 缩略词全大写,但处于开头时且无需作为导出或者public则使用小写
  • 变量距离使用地方越远则需要携带更多上下文信息,例如全局变量
  • 对外函数尽量使用富有信息量的参数名称
  • 函数名尽量短且不携带包名的上下文
  • 包名只使用小写字母,不用其他字符包括下划线,且能够包含一定的上下文信息,尽量缩写

编码规范:

  • 尽量报错代码最小缩进(即减少if和for)
  • erros.New来创建匿名变量来直接表示简单错误
  • 格式化错误则用fmt.Errorf
  • 利用errors.Is处理指定类型的错误
  • erros.As可以获取特定类型的错误
  • 不建议业务代码使用panic(但在启动阶段可以使用,尽早处理错误)

性能优化建议

优化的前提:程序正确,在此基础上依据测试数据再进行优化

benchmark 是 go自带的基准性能测试工具
slice初始化时先声明好大小
slice的陷阱: 在原有切片基础创建切片是不会释放原有数组,而且在其基础上创建小切片(利用copy代替创建切片操作)
map也是一样需要预分配
strings.Builder和bytes.Buffer由于其底层是[]byte数组,由于内存扩容策略无需每次拼接都分配新内存
builder.Grow(实质需要多少内存) -- 提前设置内存大小

原子操作的包atomic, 原子操作是靠硬件实现不同于锁(系统调用)
避免常见的性能陷阱其实就能提升较大的性能了
不要过度和过早优化,应该依照数据指标

性能分析工具pprof

使用方法:
go tool pprof "http://localhost:6060/debug/pprof/profile?seconds=10"
输入top:flat当前函数本身的执行耗时,flat%flat占CPU总时间的比例,sum%上面每一行flat%总和,cum指当前函数本身加上其调用函数的总耗时,cum% cum占CPU总时间的比例

图示化查看性能相关信息(heap改成其他的也可以,详细看http://localhost:6060/debug/pprof/ 即可) go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/heap"

Hep———SAMPLE:

  • alloc_objects: 程序累计申请的对象数
  • alloc_space: 程序累计申请的内存大小、
  • inuse_objects: 程序当前持有的对象数
  • inuse_space: 程序当前占用的内存大小

服务性能评估手段

  • 服务性能评估方式

    • 单独benchmark无法满足复杂逻辑分析
    • 不同负载情况下性能表现差异
  • 请求流量构造

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

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

    • 单机性能数据
    • 集群性能数据

业务服务优化

上线后:重复压测验证,关注服务监控,逐步放量,收集性能数据
规范上游服务调用接口,明确场景需求(防止重复调用)
分析链路,通过业务流程优化提升服务性能

基础库优化

AB实验SDK的优化
  • 分析基础库核心逻辑和性能瓶颈(设计完善改造方案,数据按需获取,数据序列化协议优化)
  • 内部压测验证
  • 推广业务服务落地验证

编译器与运行时优化

  • 优化内存分配策略,编译流程
  • 内部压测验证
  • 推广业务服务落地验证