Skillshub golang-concurrency
Golang concurrency patterns. Use when writing or reviewing concurrent Go code involving goroutines, channels, select, locks, sync primitives, errgroup, singleflight, worker pools, or fan-out/fan-in pipelines. Also triggers when you detect goroutine leaks, race conditions, channel ownership issues, or need to choose between channels and mutexes.
git clone https://github.com/ComeOnOliver/skillshub
T=$(mktemp -d) && git clone --depth=1 https://github.com/ComeOnOliver/skillshub "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/Harmeet10000/skills/golang-concurrency" ~/.claude/skills/comeonoliver-skillshub-golang-concurrency && rm -rf "$T"
skills/Harmeet10000/skills/golang-concurrency/SKILL.mdPersona: 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
skill takes precedence.samber/cc-skills-golang@golang-concurrency
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<-
) — 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 cancellationctx.Done() - Never use
in loops — each call creates a timer that lives until it fires, accumulating memory. Usetime.After
+time.NewTimerReset - 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 | / | 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 |
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 |
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 +map when writes dominate |
| Reuse temporary objects | Always before ; reduces GC pressure |
| One-time initialization | Go 1.21+: , , |
| Wait for goroutine completion | before ; Go 1.24+: simplifies usage |
| Deduplicate concurrent calls | Cache stampede prevention |
| Goroutine group + errors | 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
or done channelcontext.Context - Can I wait for it? —
orsync.WaitGrouperrgroup - 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
) 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, missingtime.After
in select, unbounded spawningctx.Done() - Check mutex usage,
, atomics, and thread-safety documentationsync.Map
Common Mistakes
| Mistake | Fix |
|---|---|
| Fire-and-forget goroutine | Provide stop mechanism (context, done channel) |
| Closing channel from receiver | Only the sender closes |
in hot loop | Reuse + |
Missing in select | Always select on context to allow cancellation |
| Unbounded goroutine spawning | Use or semaphore |
| Sharing pointer via channel | Send copies or immutable values |
inside goroutine | Call before — may return early otherwise |
Forgetting in CI | Always run |
| Mutex held across I/O | Keep critical sections short |
Cross-References
- -> See
skill for false sharing, cache-line padding,samber/cc-skills-golang@golang-performance
hot-path patternssync.Pool - -> See
skill for cancellation propagation and timeout patternssamber/cc-skills-golang@golang-context - -> See
skill for concurrent map access and race condition preventionsamber/cc-skills-golang@golang-safety - -> See
skill for debugging goroutine leaks and deadlockssamber/cc-skills-golang@golang-troubleshooting - -> See
skill for graceful shutdown patternssamber/cc-skills-golang@golang-design-patterns