Go编程与性能调优 | 青训营笔记

55 阅读3分钟

Go编程与性能调优 | 青训营笔记

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

1.1 高质量Go编写

“简单、可读、生产力”
  • 边界条件完备
  • 异常情况处理
  • 易读易维护

1.2 编码规范:

  • 命名规范(避免包内调用命名重复eg:time.NowTime,以及包内其他含义的命名不可省略eg:time.ParseDuration 而不是 time.Parse,参考开源的代码规范文档)
  • 控制流程(避免嵌套,最小缩小,优先返回)
  • 错误和异常处理:优先使用简单错误创建匿名变量errors.New(),有格式化或错误关联需求用fmt.Errorf(),错误判定:errors.Is()/errors.As(),启动阶段不可逆转的错误使用panic,其余时间尽量使用error代替panic,需要更多的上下文信息则采用recover(),recover后可记录当前调用栈,生效范围:当前goroutine的被defer的函数中生效,defer:函数最后返回前调用,后进先出
  • 自动格式化代码工具(gofmt,goimports = gofmt+依赖包管理)
  • 注释(对外提供的公共符号,实现过程及功能)

1.3 性能优化

(1) 基准性能测试工具:benchmark (2) 优化建议:

  • slice切片、map预分配内存,避免动态扩容操作导致的重复申请和拷贝问题
  • copy代替re-slice,避免原底层数组有引用,得不到释放,切片本质是一个数组片段的描述,包括数组指针、片段长度和容量,切片操作并不复制切片指向元素,创建新切片会复用原切片的底层数组
  • 字符串处理:使用strings.Builder,优于直接str操作或bytes.Buffer
  • 使用空结构体作为占位符,实例:用map实现Set,只使用键,而不需要值,用空结构体占位
  • 使用atomic包:通过硬件实现,效率比锁高

“避免常见的性能陷阱可以保证大部分性能,但不必一味追求程序性能”

1.4 性能分析工具

pprof:用于可视化和分析性能分析数据的工具

实践项目:github.com/wolfogre/go…

import{
    "net/http"
    "net/http/pprof"   //自动注册pprof的handler到http server
}

(1)功能简介

查看程序的CPU、内存、协程、锁、阻塞、线程创建等使用情况,运行后,

web端查看:http://localhost:6060/debug/pprof

命令行获取:

go tool pprof "http://localhost:6060/debug/pprof/profile?seconds=10" //seconds= 设置采样时间
web //web命令用于可视化调用关系
  • alloc_objects: 程序累计申请的对象数
  • inuse_objects: 程序当前持有的对象数
  • alloc_space: 程序累计申请的内存大小
  • inuse_space: 程序当前占用的内存大小

(2)采样过程和原理(上述四种采样指标)

  • CPU: 100次/秒
  • Heap: 1次/512KB
  • Goroutine:记录所有用户发起且在运行中的goroutine
  • ThreadCreate:记录程序创建的所有系统线程信息
  • Block:记录阻塞操作的次数和耗时,耗时超过阈值才会被记录,采样率自设置,设置为1代表每次阻塞都记录
  • Mutex:记录争抢锁的次数和耗时,只记录固定比例的锁操作,采样率自设置,设置为1代表每次加锁都记录

1.5 工程中性能优化的原则和流程

性能调优案例:

  • 业务服务优化 规范上游调用接口,分析服务链路
  • 基础库优化 基础库的核心逻辑和性能瓶颈:数据按需获取,序列化协议
  • Go语言优化 调整编译配置,优化内存分配策略