Golang Concurrency
/install golang-concurrency
Persona: 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 supersedes
samber/cc-skills-golang@golang-concurrencyskill takes precedence.
Go Concurrency Best Practices
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.
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\x3C-,\x3C-chan) — the compiler prevents misuse at build time - Default to unbuffered channels — larger buffers mask backpressure; use them only with measured justification
- Always include
ctx.Done()in select — without it, goroutines leak after caller cancellation - Never use
time.Afterin loops — each call creates a timer that lives until it fires, accumulating memory. Usetime.NewTimer+Reset - Track goroutine leaks in tests with
go.uber.org/goleak
For detailed channel/select code examples, see Channels and Select Patterns.
Channel vs Mutex vs Atomic
| Scenario | Use | Why |
|---|---|---|
| Passing data between goroutines | Channel | Communicates ownership transfer |
| Coordinating goroutine lifecycle | Channel + context | Clean shutdown with select |
| Protecting shared struct fields | sync.Mutex / sync.RWMutex |
Simple critical sections |
| Simple counters, flags | sync/atomic |
Lock-free, lower overhead |
| Many readers, few writers on a map | sync.Map |
Optimized for read-heavy workloads. Concurrent map read/write causes a hard crash |
| Caching expensive computations | sync.Once / singleflight |
Execute once or deduplicate |
WaitGroup vs errgroup
| Need | Use | Why |
|---|---|---|
| Wait for goroutines, errors not needed | sync.WaitGroup |
Fire-and-forget |
| Wait + collect first error | errgroup.Group |
Error propagation |
| Wait + cancel siblings on first error | errgroup.WithContext |
Context cancellation on error |
| Wait + limit concurrency | errgroup.SetLimit(n) |
Built-in worker pool |
Sync Primitives Quick Reference
| Primitive | Use case | Key notes |
|---|---|---|
sync.Mutex |
Protect shared state | Keep critical sections short; never hold across I/O |
sync.RWMutex |
Many readers, few writers | Never upgrade RLock to Lock (deadlock) |
sync/atomic |
Simple counters, flags | Prefer typed atomics (Go 1.19+): atomic.Int64, atomic.Bool |
sync.Map |
Concurrent map, read-heavy | No explicit locking; use RWMutex+map when writes dominate |
sync.Pool |
Reuse temporary objects | Always Reset() before Put(); reduces GC pressure |
sync.Once |
One-time initialization | Go 1.21+: OnceFunc, OnceValue, OnceValues |
sync.WaitGroup |
Wait for goroutine completion | Add before go; Go 1.24+: wg.Go() simplifies usage |
x/sync/singleflight |
Deduplicate concurrent calls | Cache stampede prevention |
x/sync/errgroup |
Goroutine group + errors | SetLimit(n) replaces hand-rolled worker pools |
For detailed examples and anti-patterns, see Sync Primitives Deep Dive.
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
context.Contextor done channel - Can I wait for it? —
sync.WaitGrouporerrgroup - Who owns the channels? — creator/sender owns and closes
- Should this be synchronous instead? — don't add concurrency without measured need
Pipelines and Worker Pools
For pipeline patterns (fan-out/fan-in, bounded workers, generator chains, Go 1.23+ iterators, samber/ro), see Pipelines and Worker Pools.
Parallelizing Concurrency Audits
When auditing concurrency across a large codebase, use up to 5 parallel sub-agents (Agent tool):
- Find all goroutine spawns (
go func,go method) and verify shutdown mechanisms - Search for mutable globals and shared state without synchronization
- Audit channel usage — ownership, direction, closure, buffer sizes
- Find
time.Afterin loops, missingctx.Done()in select, unbounded spawning - Check mutex usage,
sync.Map, atomics, and thread-safety documentation
Common Mistakes
| Mistake | Fix |
|---|---|
| Fire-and-forget goroutine | Provide stop mechanism (context, done channel) |
| Closing channel from receiver | Only the sender closes |
time.After in hot loop |
Reuse time.NewTimer + Reset |
Missing ctx.Done() in select |
Always select on context to allow cancellation |
| Unbounded goroutine spawning | Use errgroup.SetLimit(n) or semaphore |
| Sharing pointer via channel | Send copies or immutable values |
wg.Add inside goroutine |
Call Add before go — Wait may return early otherwise |
Forgetting -race in CI |
Always run go test -race ./... |
| Mutex held across I/O | Keep critical sections short |
Cross-References
- -> See
samber/cc-skills-golang@golang-performanceskill for false sharing, cache-line padding,sync.Poolhot-path patterns - -> See
samber/cc-skills-golang@golang-contextskill for cancellation propagation and timeout patterns - -> See
samber/cc-skills-golang@golang-safetyskill for concurrent map access and race condition prevention - -> See
samber/cc-skills-golang@golang-troubleshootingskill for debugging goroutine leaks and deadlocks - -> See
samber/cc-skills-golang@golang-design-patternsskill for graceful shutdown patterns - -> See
samber/cc-skills-golang@golang-continuous-integrationskill for automated AI-driven code review in CI using these guidelines
References
- 确保已安装 OpenClaw(本地或 Docker 部署)
- 在对话框中输入安装命令:
/install golang-concurrency - 安装完成后,直接呼叫该 Skill 的名称或使用
/golang-concurrency触发 - 根据 Skill 的参数说明提供必要输入,即可获得结构化输出
Golang Concurrency 是什么?
Golang concurrency patterns. Use when writing or reviewing concurrent Go code involving goroutines, channels, select, locks, sync primitives, errgroup, singl... 它是一个面向 Claude Code / OpenClaw 的 AI Agent Skill 插件,目前累计下载 185 次。
如何安装 Golang Concurrency?
在 OpenClaw 或 Claude Code 对话框中运行命令「/install golang-concurrency」即可一键安装,无需额外配置。
Golang Concurrency 是免费的吗?
是的,Golang Concurrency 完全免费,采用 MIT-0 许可证,可自由下载、安装和使用。
Golang Concurrency 支持哪些平台?
Golang Concurrency 跨平台运行,可在任意部署了 OpenClaw / Claude Code 的环境中使用(cross-platform)。
谁开发了 Golang Concurrency?
由 Samuel Berthe(@samber)开发并维护,当前版本 v1.1.1。