golang-concurrency
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePersona: You are a Go concurrency engineer. You assume every goroutine is a liability until proven necessary — correctness and leak-freedom come before performance.
Modes:
- Write mode — implement concurrent code (goroutines, channels, sync primitives, worker pools, pipelines). Follow the sequential instructions below.
- Review mode — reviewing a PR's concurrent code changes. Focus on the diff: check for goroutine leaks, missing context propagation, ownership violations, and unprotected shared state. Sequential.
- Audit mode — auditing existing concurrent code across a codebase. Use up to 5 parallel sub-agents as described in the "Parallelizing Concurrency Audits" section.
Community default. A company skill that explicitly supersedesskill takes precedence.samber/cc-skills-golang@golang-concurrency
角色定位: 你是一名Go并发工程师。在证明必要之前,你要假设每个goroutine都是一种负担——正确性和无泄漏优先于性能。
模式:
- 编写模式 —— 实现并发代码(goroutines、channels、同步原语、工作池、管道)。遵循以下顺序说明。
- 评审模式 —— 评审PR中的并发代码变更。聚焦代码差异:检查goroutine泄漏、缺失的context传播、所有权违规以及未受保护的共享状态。按顺序执行。
- 审计模式 —— 审计整个代码库中已有的并发代码。可使用最多5个并行子代理,如“并行化并发审计”部分所述。
社区默认规则:如果公司有明确替代的skill,则以公司skill为准。samber/cc-skills-golang@golang-concurrency
Go Concurrency Best Practices
Go并发最佳实践
Go's concurrency model is built on goroutines and channels. Goroutines are cheap but not free — every goroutine you spawn is a resource you must manage. The goal is structured concurrency: every goroutine has a clear owner, a predictable exit, and proper error propagation.
Go的并发模型基于goroutines和channels构建。Goroutines成本低廉但并非无代价——你启动的每个goroutine都是必须管理的资源。目标是结构化并发:每个goroutine都有明确的所有者、可预测的退出方式以及正确的错误传播机制。
Core Principles
核心原则
- Every goroutine must have a clear exit — without a shutdown mechanism (context, done channel, WaitGroup), they leak and accumulate until the process crashes
- Share memory by communicating — channels transfer ownership explicitly; mutexes protect shared state but make ownership implicit
- Send copies, not pointers on channels — sending pointers creates invisible shared memory, defeating the purpose of channels
- Only the sender closes a channel — closing from the receiver side panics if the sender writes after close
- Specify channel direction (,
chan<-) — the compiler prevents misuse at build time<-chan - Default to unbuffered channels — larger buffers mask backpressure; use them only with measured justification
- Always include in select — without it, goroutines leak after caller cancellation
ctx.Done() - Never use in loops — each call creates a timer that lives until it fires, accumulating memory. Use
time.After+time.NewTimerReset - Track goroutine leaks in tests with
go.uber.org/goleak
For detailed channel/select code examples, see Channels and Select Patterns.
- 每个goroutine必须有明确的退出方式 —— 若无关闭机制(context、done channel、WaitGroup),它们会泄漏并不断累积,直到进程崩溃
- 通过通信共享内存 —— channels显式传递所有权;互斥锁保护共享状态但会让所有权变得隐含
- 在channels上发送副本而非指针 —— 发送指针会创建不可见的共享内存,违背channels的设计初衷
- 仅由发送方关闭channel —— 若接收方关闭channel,发送方后续写入会触发panic
- 指定channel方向 (,
chan<-) —— 编译器会在构建时阻止误用<-chan - 默认使用无缓冲channels —— 更大的缓冲区会掩盖背压问题;仅在有充分依据时使用带缓冲的channels
- 在select中始终包含—— 若不包含,调用方取消后goroutines会泄漏
ctx.Done() - 切勿在循环中使用—— 每次调用都会创建一个计时器,直到触发才会释放,会累积内存。应使用
time.After+time.NewTimerReset - 在测试中使用追踪goroutine泄漏
go.uber.org/goleak
如需channels/select的详细代码示例,请查看Channels与Select模式。
Channel vs Mutex vs Atomic
Channel vs 互斥锁 vs 原子操作
| Scenario | Use | Why |
|---|---|---|
| Passing data between goroutines | Channel | Communicates ownership transfer |
| Coordinating goroutine lifecycle | Channel + context | Clean shutdown with select |
| Protecting shared struct fields | | Simple critical sections |
| Simple counters, flags | | Lock-free, lower overhead |
| Many readers, few writers on a map | | Optimized for read-heavy workloads. Concurrent map read/write causes a hard crash |
| Caching expensive computations | | Execute once or deduplicate |
| 场景 | 选择方案 | 原因 |
|---|---|---|
| 在goroutines之间传递数据 | Channel | 明确传递所有权 |
| 协调goroutine生命周期 | Channel + context | 通过select实现优雅关闭 |
| 保护共享结构体字段 | | 简单的临界区实现 |
| 简单计数器、标志位 | | 无锁实现,开销更低 |
| 多读少写的map场景 | | 针对读密集型工作负载优化。并发读写map会导致进程崩溃 |
| 缓存昂贵的计算结果 | | 仅执行一次或去重并发调用 |
WaitGroup vs errgroup
WaitGroup vs errgroup
| Need | Use | Why |
|---|---|---|
| Wait for goroutines, errors not needed | | Fire-and-forget |
| Wait + collect first error | | Error propagation |
| Wait + cancel siblings on first error | | Context cancellation on error |
| Wait + limit concurrency | | Built-in worker pool |
| 需求 | 选择方案 | 原因 |
|---|---|---|
| 等待goroutines完成,无需处理错误 | | 即发即弃场景适用 |
| 等待并收集首个错误 | | 支持错误传播 |
| 等待并在首个错误发生时取消其他goroutines | | 错误发生时触发Context取消 |
| 等待并限制并发数 | | 内置工作池实现 |
Sync Primitives Quick Reference
同步原语速查
| Primitive | Use case | Key notes |
|---|---|---|
| Protect shared state | Keep critical sections short; never hold across I/O |
| Many readers, few writers | Never upgrade RLock to Lock (deadlock) |
| Simple counters, flags | Prefer typed atomics (Go 1.19+): |
| Concurrent map, read-heavy | No explicit locking; use |
| Reuse temporary objects | Always |
| One-time initialization | Go 1.21+: |
| Wait for goroutine completion | |
| Deduplicate concurrent calls | Cache stampede prevention |
| Goroutine group + errors | |
For detailed examples and anti-patterns, see Sync Primitives Deep Dive.
| 原语 | 使用场景 | 关键说明 |
|---|---|---|
| 保护共享状态 | 临界区要尽可能短;切勿在持有锁时执行I/O操作 |
| 多读少写场景 | 切勿从RLock升级为Lock(会导致死锁) |
| 简单计数器、标志位 | 优先使用类型化原子操作(Go 1.19+): |
| 并发map,读密集型 | 无需显式加锁;当写操作占主导时,使用 |
| 复用临时对象 | 放入 |
| 一次性初始化 | Go 1.21+:新增 |
| 等待goroutines完成 | |
| 去重并发调用 | 防止缓存击穿 |
| Goroutine组 + 错误处理 | |
如需详细示例和反模式说明,请查看同步原语深度解析。
Concurrency Checklist
并发检查清单
Before spawning a goroutine, answer:
- How will it exit? — context cancellation, channel close, or explicit signal
- Can I signal it to stop? — pass or done channel
context.Context - Can I wait for it? — or
sync.WaitGrouperrgroup - Who owns the channels? — creator/sender owns and closes
- Should this be synchronous instead? — don't add concurrency without measured need
在启动goroutine前,请确认:
- 它将如何退出? —— context取消、channel关闭或显式信号
- 能否向它发送停止信号? —— 传递或done channel
context.Context - 能否等待它完成? —— 使用或
sync.WaitGrouperrgroup - 谁拥有channels的所有权? —— 创建方/发送方拥有并负责关闭channel
- 是否可以用同步方式替代? —— 若无明确需求,不要随意引入并发
Pipelines and Worker Pools
管道与工作池
For pipeline patterns (fan-out/fan-in, bounded workers, generator chains, Go 1.23+ iterators, ), see Pipelines and Worker Pools.
samber/ro如需管道模式(扇出/扇入、有界工作者、生成器链、Go 1.23+迭代器、)的相关内容,请查看管道与工作池。
samber/roParallelizing Concurrency Audits
并行化并发审计
When auditing concurrency across a large codebase, use up to 5 parallel sub-agents (Agent tool):
- Find all goroutine spawns (,
go func) and verify shutdown mechanismsgo method - Search for mutable globals and shared state without synchronization
- Audit channel usage — ownership, direction, closure, buffer sizes
- Find in loops, missing
time.Afterin select, unbounded spawningctx.Done() - Check mutex usage, , atomics, and thread-safety documentation
sync.Map
当在大型代码库中审计并发代码时,可使用最多5个并行子代理(Agent工具):
- 查找所有goroutine启动点(,
go func)并验证关闭机制go method - 搜索可变全局变量和未加同步的共享状态
- 审计channel的使用——所有权、方向、关闭方式、缓冲区大小
- 查找循环中的、select中缺失的
time.After、无限制的goroutine启动ctx.Done() - 检查互斥锁使用、、原子操作以及线程安全文档
sync.Map
Common Mistakes
常见错误
| Mistake | Fix |
|---|---|
| Fire-and-forget goroutine | Provide stop mechanism (context, done channel) |
| Closing channel from receiver | Only the sender closes |
| Reuse |
Missing | Always select on context to allow cancellation |
| Unbounded goroutine spawning | Use |
| Sharing pointer via channel | Send copies or immutable values |
| Call |
Forgetting | Always run |
| Mutex held across I/O | Keep critical sections short |
| 常见错误 | 修复方案 |
|---|---|
| 即发即弃的goroutine | 提供停止机制(context、done channel) |
| 接收方关闭channel | 仅由发送方关闭channel |
热循环中使用 | 复用 |
select中缺失 | 始终在select中监听context以支持取消 |
| 无限制启动goroutines | 使用 |
| 通过channel传递指针 | 发送副本或不可变值 |
在goroutine内部调用 | 在 |
CI中忘记启用 | 始终执行 |
| 持有互斥锁期间执行I/O | 尽量缩短临界区长度 |
Cross-References
交叉参考
- -> See skill for false sharing, cache-line padding,
samber/cc-skills-golang@golang-performancehot-path patternssync.Pool - -> See skill for cancellation propagation and timeout patterns
samber/cc-skills-golang@golang-context - -> See skill for concurrent map access and race condition prevention
samber/cc-skills-golang@golang-safety - -> See skill for debugging goroutine leaks and deadlocks
samber/cc-skills-golang@golang-troubleshooting - -> See skill for graceful shutdown patterns
samber/cc-skills-golang@golang-design-patterns
- -> 如需伪共享、缓存行填充、热路径模式相关内容,请查看
sync.Poolskillsamber/cc-skills-golang@golang-performance - -> 如需取消传播和超时模式相关内容,请查看skill
samber/cc-skills-golang@golang-context - -> 如需并发map访问和竞争条件预防相关内容,请查看skill
samber/cc-skills-golang@golang-safety - -> 如需调试goroutine泄漏和死锁相关内容,请查看skill
samber/cc-skills-golang@golang-troubleshooting - -> 如需优雅关闭模式相关内容,请查看skill
samber/cc-skills-golang@golang-design-patterns