golang-performance

golang-performance

热门

Golang 性能优化模式与方法论——如果存在 X 瓶颈,则应用 Y。涵盖内存分配减少、CPU 效率、内存布局、GC 调优、池化、缓存和热路径优化。当性能分析或基准测试已识别出瓶颈,且需要正确的优化模式来修复时使用。也用于执行性能代码审查,以提出改进建议或有助于快速识别性能提升的基准测试。不适用于测量方法论(→ 参见 `samber/cc-skills-golang@golang-benchmark` 技能)或调试工作流(→ 参见 `samber/cc-skills-golang@golang-troubleshooting` 技能)。

2261Star
150Fork
更新于 2026/6/6
SKILL.md
只读
名称
golang-performance
描述

Golang 性能优化模式与方法论——如果存在 X 瓶颈,则应用 Y。涵盖内存分配减少、CPU 效率、内存布局、GC 调优、池化、缓存和热路径优化。当性能分析或基准测试已识别出瓶颈,且需要正确的优化模式来修复时使用。也用于执行性能代码审查,以提出改进建议或有助于快速识别性能提升的基准测试。不适用于测量方法论(→ 参见 `samber/cc-skills-golang@golang-benchmark` 技能)或调试工作流(→ 参见 `samber/cc-skills-golang@golang-troubleshooting` 技能)。

角色: 你是一名 Go 性能工程师。没有性能分析绝不优化——测量、假设、改动一处、重新测量。

思维模式: 使用 ultrathink 进行性能优化。浅层分析会误判瓶颈——深度推理确保将正确的优化应用于正确的问题。

模式:

  • 审查模式(架构)——对包或服务进行广泛扫描,查找结构性反模式(缺少连接池、无界 goroutine、错误的数据结构)。最多使用 3 个并行子代理,按关注点拆分:(1) 分配和内存布局,(2) I/O 和并发,(3) 算法复杂度和缓存。
  • 审查模式(热路径)——对调用者指定的单个函数或紧凑循环进行聚焦分析。顺序执行;一个子代理就足够了。
  • 优化模式——性能分析已识别出瓶颈。按迭代周期(定义指标 → 基线 → 诊断 → 改进 → 比较)顺序执行——一次只改一处是纪律。

依赖:

  • benchstat:go install golang.org/x/perf/cmd/benchstat@latest

Go 性能优化

核心理念

  1. 先性能分析,后优化——关于瓶颈的直觉大约 80% 是错误的。使用 pprof 查找实际热点(→ 参见 samber/cc-skills-golang@golang-troubleshooting 技能)
  2. 减少内存分配带来最大回报——Go 的 GC 很快,但并非免费。减少每次请求的分配通常比微优化 CPU 更重要
  3. 记录优化——添加代码注释解释为什么某个模式更快,并在可能时附上基准测试数据。未来的读者需要上下文,以避免还原一个“不必要”的优化

首先排除外部瓶颈

在优化 Go 代码之前,确认瓶颈在你的进程中——如果 90% 的延迟来自慢速数据库查询或 API 调用,减少分配也无济于事。

诊断: 1- fgprof——捕获 CPU 内和 CPU 外(I/O 等待)时间;如果 CPU 外占主导,则瓶颈是外部的 2- go tool pprof(goroutine 分析)——许多 goroutine 阻塞在 net.(*conn).Readdatabase/sql = 外部等待 3- 分布式追踪(OpenTelemetry)——跨度分解显示哪个上游较慢

当瓶颈在外部时: 改为优化该组件——查询调优、缓存、连接池、熔断器(→ 参见 samber/cc-skills-golang@golang-database 技能,缓存模式)。

迭代优化方法论

循环:定义目标 → 基准测试 → 诊断 → 改进 → 基准测试

  1. 定义你的指标——延迟、吞吐量、内存还是 CPU?没有目标,优化就是随机的
  2. 编写原子基准测试——每个基准测试隔离一个函数,避免结果污染(→ 参见 samber/cc-skills-golang@golang-benchmark 技能)
  3. 测量基线——go test -bench=BenchmarkMyFunc -benchmem -count=6 ./pkg/... | tee /tmp/report-1.txt
  4. 诊断——使用每个深入章节中的诊断行来选择正确的工具
  5. 改进——一次只应用一个优化,并附上解释性注释
  6. 比较——benchstat /tmp/report-1.txt /tmp/report-2.txt 确认统计显著性
  7. 提交——将 benchstat 输出粘贴到提交正文中,以便审查者和未来读者看到确切的改进;遵循 perf(scope): summary 提交类型
  8. 重复——递增报告编号,处理下一个瓶颈

在发明自定义解决方案之前,参考库文档了解已知模式。保留所有 /tmp/report-*.txt 文件作为审计追踪。

决策树:时间花在哪里?

瓶颈 信号(来自 pprof) 操作
分配过多 堆分析中 alloc_objects 内存优化
CPU 密集型热循环 函数在 CPU 分析中占主导 CPU 优化
GC 暂停 / OOM GC% 高,容器限制 运行时调优
网络 / I/O 延迟 goroutine 阻塞在 I/O 上 I/O 与网络
重复的昂贵工作 多次相同计算/获取 缓存模式
错误算法 O(n²) 但存在 O(n) 算法复杂度
锁竞争 mutex/block 分析热点 → 参见 samber/cc-skills-golang@golang-concurrency 技能
慢查询 DB 时间在追踪中占主导 → 参见 samber/cc-skills-golang@golang-database 技能

常见错误

错误 修复
未经性能分析就优化 先用 pprof 分析——直觉大约 80% 是错误的
默认 http.Client 未设置 Transport MaxIdleConnsPerHost 默认为 2;设置为匹配你的并发级别
在热循环中记录日志 日志调用阻止内联,即使级别被禁用也会分配内存。使用 slog.LogAttrs
panic/recover 作为控制流 panic 会分配堆栈跟踪并展开堆栈;使用错误返回
未经基准测试证明就使用 unsafe 仅在性能分析显示已验证热路径中改进 >10% 时才合理
在容器中未进行 GC 调优 GOMEMLIMIT 设置为容器内存的 80-90% 以防止 OOM 杀死
在生产中使用 reflect.DeepEqual 比类型化比较慢 50-200 倍;使用 slices.Equalmaps.Equalbytes.Equal

深入章节

  • 内存优化 —— 分配模式、后备数组泄漏、sync.Pool、结构体对齐
  • CPU 优化 —— 内联、缓存局部性、伪共享、ILP、避免反射
  • I/O 与网络 —— HTTP 传输配置、流式处理、JSON 性能、cgo、批量操作
  • 运行时调优 —— GOGC、GOMEMLIMIT、GC 诊断、GOMAXPROCS、PGO
  • 缓存模式 —— 算法复杂度、编译模式、singleflight、避免工作
  • 生产可观测性 —— Prometheus 指标、PromQL 查询、持续性能分析、告警规则

CI 回归检测

在 CI 中自动化基准测试比较,以在回归到达生产之前捕获它们。→ 参见 samber/cc-skills-golang@golang-benchmark 技能了解 benchdiffcob 设置。

交叉引用

  • → 参见 samber/cc-skills-golang@golang-benchmark 技能了解基准测试方法论、benchstatb.Loop()(Go 1.24+)
  • → 参见 samber/cc-skills-golang@golang-troubleshooting 技能了解 pprof 工作流、逃逸分析诊断和性能调试
  • → 参见 samber/cc-skills-golang@golang-data-structures 技能了解切片/映射预分配和 strings.Builder
  • → 参见 samber/cc-skills-golang@golang-concurrency 技能了解工作池、sync.Pool API、goroutine 生命周期和锁竞争
  • → 参见 samber/cc-skills-golang@golang-safety 技能了解循环中的 defer、切片后备数组别名
  • → 参见 samber/cc-skills-golang@golang-database 技能了解连接池调优和批处理
  • → 参见 samber/cc-skills-golang@golang-observability 技能了解生产环境中的持续性能分析