mcpField
G
golang-concurrency

golang-concurrency

github.com/samber开发3.7k42.2k 次安装5 天前更新
代码仓库

关于 golang-concurrency

golang-concurrency 是面向 Go 开发的编码技能,涵盖并发代码的编写、评审和审计。它侧重 goroutine 生命周期、所有权、取消机制与结构化错误处理,并提供大型代码库的并行审计方法。

主要功能

  1. 01编写、评审和审计模式
  2. 02goroutine 生命周期与泄漏预防
  3. 03通道所有权和同步指导
  4. 04工作池与流水线模式
  5. 05最多五个子 Agent 并行审计

适用场景

  1. 01检查 Pull Request 中的并发缺陷
  2. 02审计代码库中的 goroutine 退出机制
  3. 03实现可取消的工作池和流水线

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/samber/cc-skills-golang --skill golang-concurrency

安装后在 Claude Code 中输入/golang-concurrency确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

evals/
evals.json
references/
channels-and-select.md
pipelines.md
sync-primitives.md

详细介绍

角色: 你是一名 Go 并发工程师。你认为每个 goroutine 在证明其必要之前都是一种负担——正确性和无泄漏优先于性能。

编排模式: 按照“并行化并发审计”一节中的说明,分派 5 个子 Agent,审计大型代码库中的并发代码,并将它们的发现汇总成一份报告。在 Claude Code 中,使用 ultracode 明确启用多 Agent 编排。

模式:

  • 编写模式 — 实现并发代码(goroutine、channel、同步原语、工作池、流水线)。遵循下方的顺序说明。
  • 审查模式 — 审查 PR 中的并发代码变更。聚焦于差异:检查 goroutine 泄漏、缺少 context 传递、所有权违规以及未受保护的共享状态。按顺序进行。
  • 审计模式 — 审计整个代码库中现有的并发代码。按照“并行化并发审计”一节中的说明,最多使用 5 个并行子 Agent。

社区默认规则。 如果公司的技能明确取代 samber/cc-skills-golang@golang-concurrency 技能,则优先采用该公司技能。

Go 并发最佳实践

Go 的并发模型基于 goroutine 和 channel。Goroutine 开销很低,但并非没有开销——每启动一个 goroutine,你都必须管理一个资源。目标是实现结构化并发:每个 goroutine 都有明确的所有者、可预期的退出方式,以及恰当的错误传递机制。

核心原则

  1. 每个 goroutine 都必须有明确的退出方式 — 没有关闭机制(context、done channel、WaitGroup),goroutine 就会泄漏并不断累积,直至进程崩溃
  2. 通过通信共享内存 — channel 可明确转移所有权;互斥锁能保护共享状态,但所有权变得隐式
  3. 通过 channel 发送副本,而不是指针 — 发送指针会产生不可见的共享内存,违背使用 channel 的初衷
  4. 只有发送方才能关闭 channel — 如果发送方在关闭后写入,从接收方一侧关闭就会导致 panic
  5. 指定 channel 方向(chan<-、<-chan)— 编译器会在构建时阻止误用
  6. 默认使用无缓冲 channel — 较大的缓冲区会掩盖背压;只有经过测量并确认有必要时才使用
  7. 始终在 select 中包含 ctx.Done() — 否则,调用方取消后 goroutine 会泄漏
  8. 避免在热点循环中反复使用 time.After — 每次调用都会分配一个计时器并造成不必要的开销;对于长期运行的循环,使用 time.NewTimer + Reset
  9. 在测试中使用 go.uber.org/goleak 跟踪 goroutine 泄漏

有关 channel/select 的详细代码示例,请参阅 Channels and Select Patterns。

Channel、Mutex 还是 Atomic

场景使用原因
在 goroutine 之间传递数据Channel明确传递所有权
协调 goroutine 的生命周期Channel + context通过 select 实现干净的关闭
保护共享结构体字段sync.Mutex / sync.RWMutex简单的临界区
简单计数器、标志sync/atomic无锁,开销更低
多读少写的 mapsync.Map针对读密集型工作负载进行了优化。并发读写 map 会导致进程直接崩溃
缓存开销高昂的计算结果sync.Once / singleflight只执行一次或进行去重

WaitGroup 还是 errgroup

需求使用原因
等待 goroutine 完成,不需要错误sync.WaitGroup即发即弃
等待并收集第一个错误errgroup.Group传递错误
等待,并在首次出错时取消其他 goroutineerrgroup.WithContext出错时取消 context
等待并限制并发数errgroup.SetLimit(n)内置工作池

同步原语速查

原语用途关键说明
sync.Mutex保护共享状态尽量缩短临界区;切勿在 I/O 期间持有锁
sync.RWMutex读多写少切勿将 RLock 升级为 Lock(会导致死锁)
sync/atomic简单计数器、标志优先使用类型化原子操作(Go 1.19+):atomic.Int64、atomic.Bool
sync.Map并发映射,读操作密集无需显式加锁;写操作占主导时,使用 RWMutex+map
sync.Pool重用临时对象调用 Put() 前务必先调用 Reset();可减少 GC 压力
sync.Once一次性初始化Go 1.21+:OnceFunc、OnceValue、OnceValues
sync.WaitGroup等待简单的 goroutineGo 1.25+:对于不会 panic 且无需传递错误的启动后等待任务,优先使用 wg.Go(func(){ ... })。Go <1.25 时使用 Add/Done。对于错误、取消或限制,使用带 context 的 errgroup。
x/sync/singleflight对并发调用去重防止缓存击穿
x/sync/errgroupgoroutine 组 + 错误SetLimit(n) 可替代手动实现的工作池

如需详细示例和反模式,请参阅 同步原语深入解析。

并发检查清单

启动 goroutine 前,请先回答:

  • 它将如何退出? — 通过 context 取消、关闭 channel 或显式信号
  • 我能否通知它停止? — 传入 context.Context 或 done channel
  • 我能否等待它? — 使用 sync.WaitGroup 或 errgroup
  • 谁拥有这些 channel? — 创建者/发送方拥有并负责关闭
  • 改为同步执行是否更合适? — 未经实际测量,不要增加并发

流水线和工作池

如需了解流水线模式(扇出/扇入、有界工作线程、生成器链、Go 1.23+ 迭代器、samber/ro),请参阅 流水线和工作池。

并行执行并发审查

审查大型代码库中的并发时,最多使用 5 个并行子 Agent:

  1. 查找所有启动 goroutine 的位置(go func、go method),并验证关闭机制
  2. 搜索缺少同步保护的可变全局变量和共享状态
  3. 审查 channel 的使用情况——所有权、方向、关闭方式、缓冲区大小
  4. 查找循环中的 time.After、select 中缺失的 ctx.Done()、无界启动 goroutine
  5. 检查互斥锁的使用、sync.Map、原子操作和线程安全文档

常见错误

错误修正方法
启动后不管的 goroutine提供停止机制(context、done channel)
接收方关闭 channel只有发送方负责关闭
热循环中使用 time.After重用 time.NewTimer 并调用 Reset
select 中缺少 ctx.Done()始终在 select 中监听 context,以便支持取消
无界启动 goroutine使用 errgroup.SetLimit(n) 或信号量
通过 channel 共享指针发送副本或不可变值
在 goroutine 内调用 wg.Add在 go 之前调用 Add——否则 Wait 可能提前返回
忘记在 CI 中使用 -race始终运行 go test -race ./...
在 I/O 期间持有互斥锁尽量缩短临界区

交叉引用

  • → 关于错误共享、缓存行填充和 sync.Pool 热路径模式,请参阅 samber/cc-skills-golang@golang-performance skill
  • → 关于取消传播和超时模式,请参阅 samber/cc-skills-golang@golang-context skill
  • → 关于并发映射访问和竞态条件防护,请参阅 samber/cc-skills-golang@golang-safety skill
  • → 关于调试 goroutine 泄漏和死锁,请参阅 samber/cc-skills-golang@golang-troubleshooting skill
  • → 关于优雅关闭模式,请参阅 samber/cc-skills-golang@golang-design-patterns skill
  • → 关于在 CI 中使用这些指南进行自动化 AI 驱动代码审查,请参阅 samber/cc-skills-golang@golang-continuous-integration skill
Goroutine 泄漏分析

Goroutine 泄漏分析(在 Go 1.26 中通过 GOEXPERIMENT=goroutineleakprofile 实验性启用)自 Go 1.27 起已在 runtime/pprof 中正式提供,无需构建标志。与下方现有工具配合使用时,它是一个适用于生产环境的泄漏信号。

curl http://localhost:6060/debug/pprof/goroutineleak?debug=2
go tool pprof http://localhost:6060/debug/pprof/goroutineleak

继续使用现有工具:

  • 测试:go.uber.org/goleak
  • 运行时计数:runtime.NumGoroutine()
  • 堆栈转储:/debug/pprof/goroutine?debug=2
  • 竞态检查:go test -race ./...

参考资料

评论

支持 Markdown