golang-concurrency-patterns by bobmatnyc/claude-mpm-skills
npx skills add https://github.com/bobmatnyc/claude-mpm-skills --skill golang-concurrency-patterns当 goroutine 的生命周期明确、通过 context.Context 传播取消操作、并且共享状态受到保护(通过通道或锁)时,Go 的并发能力可以很好地扩展。应用这些模式来构建可靠的服务,并避免常见的故障模式:goroutine 泄漏、死锁和数据竞争。
默认构建模块
context 来驱动取消操作和截止时间。errgroup.WithContext 来实现支持提前中止的扇出/扇入模式。避免
time.After。将 goroutine 视为具有明确所有者和关闭条件的资源。
✅ 正确:通过 context 停止 goroutine
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go func() {
ticker := time.NewTicker(250 * time.Millisecond)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
// do work
}
}
}()
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
❌ 错误:没有停止条件的 goroutine
go func() {
for {
doWork() // 永远泄漏
}
}()
✅ 正确:一个 goroutine 拥有 map
type req struct {
key string
reply chan<- int
}
func mapOwner(ctx context.Context, in <-chan req) {
m := map[string]int{}
for {
select {
case <-ctx.Done():
return
case r := <-in:
r.reply <- m[r.key]
}
}
}
✅ 正确:互斥锁保护共享 map
type SafeMap struct {
mu sync.RWMutex
m map[string]int
}
func (s *SafeMap) Get(k string) (int, bool) {
s.mu.RLock()
defer s.mu.RUnlock()
v, ok := s.m[k]
return v, ok
}
errgroup)使用 errgroup.WithContext 来运行并发任务,在出错时取消同级任务,并等待完成。
✅ 正确:在第一个错误时取消
g, ctx := errgroup.WithContext(ctx)
for _, id := range ids {
id := id // 捕获变量
g.Go(func() error {
return process(ctx, id)
})
}
if err := g.Wait(); err != nil {
return err
}
❌ 错误:WaitGroup 会丢失第一个错误且不传播取消
var wg sync.WaitGroup
for _, id := range ids {
wg.Add(1)
go func() {
defer wg.Done()
_ = process(context.Background(), id) // 忽略了调用者的 ctx + 捕获了 id
}()
}
wg.Wait()
限制并行度以防止 CPU/内存耗尽和下游过载。
✅ 正确:有界扇出
limit := make(chan struct{}, 8) // 最大 8 个并发
g, ctx := errgroup.WithContext(ctx)
for _, id := range ids {
id := id
g.Go(func() error {
select {
case <-ctx.Done():
return ctx.Err()
case limit <- struct{}{}:
}
defer func() { <-limit }()
return process(ctx, id)
})
}
return g.Wait()
使用固定数量的工作器以获得稳定的吞吐量和可预测的资源使用。
✅ 正确:带 context 停止的工作池
type Job struct{ ID string }
func runPool(ctx context.Context, jobs <-chan Job, workers int) error {
g, ctx := errgroup.WithContext(ctx)
for i := 0; i < workers; i++ {
g.Go(func() error {
for {
select {
case <-ctx.Done():
return ctx.Err()
case j, ok := <-jobs:
if !ok {
return nil
}
if err := handleJob(ctx, j); err != nil {
return err
}
}
}
})
}
return g.Wait()
}
优先使用单向通道,并且只从发送端关闭。
✅ 正确:发送者关闭
func stageA(ctx context.Context, out chan<- int) {
defer close(out)
for i := 0; i < 10; i++ {
select {
case <-ctx.Done():
return
case out <- i:
}
}
}
❌ 错误:接收者关闭
func stageB(in <-chan int) {
close(in) // 编译错误 in<-chan; 也是错误的所有权模型
}
time.Ticker vs time.After)在循环中使用 time.NewTicker;避免在热点路径中使用 time.After 分配内存。
✅ 正确:ticker
t := time.NewTicker(1 * time.Second)
defer t.Stop()
for {
select {
case <-ctx.Done():
return
case <-t.C:
poll()
}
}
❌ 错误:在循环中使用 time.After
for {
select {
case <-ctx.Done():
return
case <-time.After(1 * time.Second):
poll()
}
}
errgroup.WithContextsync.WaitGroup使用竞争检测器运行针对性测试,并在调试期间禁用缓存:
go test -race ./...
go test -run TestName -race -count=1 ./...
✅ 正确:通过 context 设置测试级超时
func TestSomething(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
if err := doThing(ctx); err != nil {
t.Fatal(err)
}
}
应对措施:
context.WithTimeout)。ok == false 时停止。<-limit 释放。go test -race 报告)应对措施:
应对措施:
ctx.Done()。time.Ticker 被停止,并且通道由发送者关闭。context.Background();传播调用者的 context。errgroup:https://pkg.go.dev/golang.org/x/sync/errgroup每周安装量
148
仓库
GitHub 星标数
27
首次出现时间
2026年1月23日
安全审计
安装于
opencode123
gemini-cli120
codex115
github-copilot112
claude-code104
cursor100
Go concurrency scales when goroutine lifetimes are explicit, cancellation is propagated with context.Context, and shared state is protected (channels or locks). Apply these patterns to build reliable services and avoid common failure modes: goroutine leaks, deadlocks, and data races.
Default building blocks
context to drive cancellation and deadlines.errgroup.WithContext for fan-out/fan-in with early abort.Avoid
time.After inside hot loops.Treat goroutines as resources with a clear owner and shutdown condition.
✅ Correct: stop goroutines via context
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go func() {
ticker := time.NewTicker(250 * time.Millisecond)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
// do work
}
}
}()
❌ Wrong: goroutine without a stop condition
go func() {
for {
doWork() // leaks forever
}
}()
✅ Correct: one goroutine owns the map
type req struct {
key string
reply chan<- int
}
func mapOwner(ctx context.Context, in <-chan req) {
m := map[string]int{}
for {
select {
case <-ctx.Done():
return
case r := <-in:
r.reply <- m[r.key]
}
}
}
✅ Correct: mutex protects shared map
type SafeMap struct {
mu sync.RWMutex
m map[string]int
}
func (s *SafeMap) Get(k string) (int, bool) {
s.mu.RLock()
defer s.mu.RUnlock()
v, ok := s.m[k]
return v, ok
}
errgroup)Use errgroup.WithContext to run concurrent tasks, cancel siblings on error, and wait for completion.
✅ Correct: cancel on first error
g, ctx := errgroup.WithContext(ctx)
for _, id := range ids {
id := id // capture
g.Go(func() error {
return process(ctx, id)
})
}
if err := g.Wait(); err != nil {
return err
}
❌ Wrong: WaitGroup loses the first error and does not propagate cancellation
var wg sync.WaitGroup
for _, id := range ids {
wg.Add(1)
go func() {
defer wg.Done()
_ = process(context.Background(), id) // ignores caller ctx + captures id
}()
}
wg.Wait()
Bound parallelism to prevent CPU/memory exhaustion and downstream overload.
✅ Correct: bounded fan-out
limit := make(chan struct{}, 8) // max 8 concurrent
g, ctx := errgroup.WithContext(ctx)
for _, id := range ids {
id := id
g.Go(func() error {
select {
case <-ctx.Done():
return ctx.Err()
case limit <- struct{}{}:
}
defer func() { <-limit }()
return process(ctx, id)
})
}
return g.Wait()
Use a fixed number of workers for stable throughput and predictable resource usage.
✅ Correct: worker pool with context stop
type Job struct{ ID string }
func runPool(ctx context.Context, jobs <-chan Job, workers int) error {
g, ctx := errgroup.WithContext(ctx)
for i := 0; i < workers; i++ {
g.Go(func() error {
for {
select {
case <-ctx.Done():
return ctx.Err()
case j, ok := <-jobs:
if !ok {
return nil
}
if err := handleJob(ctx, j); err != nil {
return err
}
}
}
})
}
return g.Wait()
}
Prefer one-directional channels and close only from the sending side.
✅ Correct: sender closes
func stageA(ctx context.Context, out chan<- int) {
defer close(out)
for i := 0; i < 10; i++ {
select {
case <-ctx.Done():
return
case out <- i:
}
}
}
❌ Wrong: receiver closes
func stageB(in <-chan int) {
close(in) // compile error in<-chan; also wrong ownership model
}
time.Ticker vs time.After)Use time.NewTicker for loops; avoid time.After allocations in hot paths.
✅ Correct: ticker
t := time.NewTicker(1 * time.Second)
defer t.Stop()
for {
select {
case <-ctx.Done():
return
case <-t.C:
poll()
}
}
❌ Wrong: time.After in loop
for {
select {
case <-ctx.Done():
return
case <-time.After(1 * time.Second):
poll()
}
}
errgroup.WithContextsync.WaitGroupRun targeted tests with the race detector and disable caching during debugging:
go test -race ./...
go test -run TestName -race -count=1 ./...
✅ Correct: test-level timeout via context
func TestSomething(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
if err := doThing(ctx); err != nil {
t.Fatal(err)
}
}
Actions:
context.WithTimeout) around blocking operations.ok == false.<-limit release in semaphore patterns.go test -race reports)Actions:
Actions:
ctx.Done().time.Ticker is stopped and channels are closed by senders.context.Background() inside request paths; propagate caller context.errgroup: https://pkg.go.dev/golang.org/x/sync/errgroupWeekly Installs
148
Repository
GitHub Stars
27
First Seen
Jan 23, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode123
gemini-cli120
codex115
github-copilot112
claude-code104
cursor100
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
113,700 周安装
Cloudflare Workers边缘环境OAuth集成指南:GitHub与Microsoft身份验证
356 周安装
Claude Code 智能体开发指南:构建高效自定义AI助手,实现任务委派与工具访问
356 周安装
asc-build-lifecycle:iOS应用构建生命周期管理工具,自动化App Store Connect流程
367 周安装
GitHub技能学习助手:从开源项目学习并创建实用技能,提升开发效率
363 周安装
隐私政策生成器 - 专业数据隐私合规专家,起草全面合规的隐私政策
373 周安装
Zustand适配器:为json-render提供状态管理后端,支持嵌套切片与Zustand v5+
368 周安装