← 返回 Skills 市场
wpank

Go Concurrency Patterns

作者 wpank · GitHub ↗ · v1.0.0
cross-platform ✓ 安全检测通过
818
总下载
0
收藏
0
当前安装
1
版本数
在 OpenClaw 中安装
/install go-concurrency-patterns
功能描述
Production Go concurrency patterns — goroutines, channels, sync primitives, context, worker pools, pipelines, and graceful shutdown. Use when building concurrent Go applications or debugging race conditions.
使用说明 (SKILL.md)

Go Concurrency Patterns

Production patterns for Go concurrency including goroutines, channels, synchronization primitives, and context management.

When to Use

  • Building concurrent Go applications
  • Implementing worker pools and pipelines
  • Managing goroutine lifecycles and cancellation
  • Debugging race conditions
  • Implementing graceful shutdown

Concurrency Primitives

Primitive Purpose When to Use
goroutine Lightweight concurrent execution Any concurrent work
channel Communication between goroutines Passing data, signaling
select Multiplex channel operations Waiting on multiple channels
sync.Mutex Mutual exclusion Protecting shared state
sync.WaitGroup Wait for goroutines to complete Coordinating goroutine completion
context.Context Cancellation and deadlines Request-scoped lifecycle management
errgroup.Group Concurrent tasks with errors Parallel work that can fail

Go Concurrency Mantra: Don't communicate by sharing memory; share memory by communicating.

Quick Start

func main() {
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()

    results := make(chan string, 10)
    var wg sync.WaitGroup

    for i := 0; i \x3C 3; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()
            select {
            case \x3C-ctx.Done():
                return
            case results \x3C- fmt.Sprintf("Worker %d done", id):
            }
        }(i)
    }

    go func() { wg.Wait(); close(results) }()

    for result := range results {
        fmt.Println(result)
    }
}

Pattern 1: Worker Pool

type Job struct {
    ID   int
    Data string
}

type Result struct {
    JobID  int
    Output string
    Err    error
}

func WorkerPool(ctx context.Context, numWorkers int, jobs \x3C-chan Job) \x3C-chan Result {
    results := make(chan Result)
    var wg sync.WaitGroup

    for i := 0; i \x3C numWorkers; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            for job := range jobs {
                select {
                case \x3C-ctx.Done():
                    return
                default:
                    results \x3C- Result{
                        JobID:  job.ID,
                        Output: fmt.Sprintf("Processed: %s", job.Data),
                    }
                }
            }
        }()
    }

    go func() { wg.Wait(); close(results) }()
    return results
}

// Usage
func main() {
    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()

    jobs := make(chan Job, 100)
    go func() {
        for i := 0; i \x3C 50; i++ {
            jobs \x3C- Job{ID: i, Data: fmt.Sprintf("job-%d", i)}
        }
        close(jobs)
    }()

    for result := range WorkerPool(ctx, 5, jobs) {
        fmt.Printf("Result: %+v\
", result)
    }
}

Pattern 2: Fan-Out / Fan-In Pipeline

// Stage 1: Generate values
func generate(ctx context.Context, nums ...int) \x3C-chan int {
    out := make(chan int)
    go func() {
        defer close(out)
        for _, n := range nums {
            select {
            case \x3C-ctx.Done(): return
            case out \x3C- n:
            }
        }
    }()
    return out
}

// Stage 2: Transform (run multiple instances for fan-out)
func square(ctx context.Context, in \x3C-chan int) \x3C-chan int {
    out := make(chan int)
    go func() {
        defer close(out)
        for n := range in {
            select {
            case \x3C-ctx.Done(): return
            case out \x3C- n * n:
            }
        }
    }()
    return out
}

// Fan-in: Merge multiple channels into one
func merge(ctx context.Context, channels ...\x3C-chan int) \x3C-chan int {
    var wg sync.WaitGroup
    out := make(chan int)

    wg.Add(len(channels))
    for _, ch := range channels {
        go func(c \x3C-chan int) {
            defer wg.Done()
            for n := range c {
                select {
                case \x3C-ctx.Done(): return
                case out \x3C- n:
                }
            }
        }(ch)
    }

    go func() { wg.Wait(); close(out) }()
    return out
}

// Usage: fan out to 3 squarers, fan in results
func main() {
    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()

    in := generate(ctx, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    c1 := square(ctx, in)
    c2 := square(ctx, in)
    c3 := square(ctx, in)

    for result := range merge(ctx, c1, c2, c3) {
        fmt.Println(result)
    }
}

Pattern 3: errgroup with Cancellation

import "golang.org/x/sync/errgroup"

func fetchAllURLs(ctx context.Context, urls []string) ([]string, error) {
    g, ctx := errgroup.WithContext(ctx)
    results := make([]string, len(urls))

    for i, url := range urls {
        i, url := i, url
        g.Go(func() error {
            req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
            if err != nil {
                return fmt.Errorf("creating request for %s: %w", url, err)
            }
            resp, err := http.DefaultClient.Do(req)
            if err != nil {
                return fmt.Errorf("fetching %s: %w", url, err)
            }
            defer resp.Body.Close()
            results[i] = fmt.Sprintf("%s: %d", url, resp.StatusCode)
            return nil
        })
    }

    if err := g.Wait(); err != nil {
        return nil, err // First error cancels all others via ctx
    }
    return results, nil
}

// With concurrency limit
func fetchWithLimit(ctx context.Context, urls []string) ([]string, error) {
    g, ctx := errgroup.WithContext(ctx)
    g.SetLimit(10) // Max concurrent goroutines
    results := make([]string, len(urls))

    for i, url := range urls {
        i, url := i, url
        g.Go(func() error {
            result, err := fetchURL(ctx, url)
            if err != nil { return err }
            results[i] = result
            return nil
        })
    }

    return results, g.Wait()
}

Pattern 4: Bounded Concurrency (Semaphore)

import "golang.org/x/sync/semaphore"

type RateLimitedWorker struct {
    sem *semaphore.Weighted
}

func NewRateLimitedWorker(maxConcurrent int64) *RateLimitedWorker {
    return &RateLimitedWorker{sem: semaphore.NewWeighted(maxConcurrent)}
}

func (w *RateLimitedWorker) Do(ctx context.Context, tasks []func() error) []error {
    var (
        wg     sync.WaitGroup
        mu     sync.Mutex
        errors []error
    )

    for _, task := range tasks {
        if err := w.sem.Acquire(ctx, 1); err != nil {
            return []error{err}
        }
        wg.Add(1)
        go func(t func() error) {
            defer wg.Done()
            defer w.sem.Release(1)
            if err := t(); err != nil {
                mu.Lock()
                errors = append(errors, err)
                mu.Unlock()
            }
        }(task)
    }

    wg.Wait()
    return errors
}

// Simpler alternative: channel-based semaphore
type Semaphore chan struct{}

func NewSemaphore(n int) Semaphore       { return make(chan struct{}, n) }
func (s Semaphore) Acquire()             { s \x3C- struct{}{} }
func (s Semaphore) Release()             { \x3C-s }

Pattern 5: Graceful Shutdown

func main() {
    ctx, cancel := context.WithCancel(context.Background())

    sigCh := make(chan os.Signal, 1)
    signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)

    server := NewServer()
    server.Start(ctx)

    sig := \x3C-sigCh
    fmt.Printf("Received signal: %v\
", sig)
    cancel() // Cancel context to stop all workers

    server.Shutdown(5 * time.Second)
}

type Server struct {
    wg sync.WaitGroup
}

func (s *Server) Start(ctx context.Context) {
    for i := 0; i \x3C 5; i++ {
        s.wg.Add(1)
        go s.worker(ctx, i)
    }
}

func (s *Server) worker(ctx context.Context, id int) {
    defer s.wg.Done()
    ticker := time.NewTicker(time.Second)
    defer ticker.Stop()

    for {
        select {
        case \x3C-ctx.Done():
            fmt.Printf("Worker %d cleaning up...\
", id)
            return
        case \x3C-ticker.C:
            fmt.Printf("Worker %d working...\
", id)
        }
    }
}

func (s *Server) Shutdown(timeout time.Duration) {
    done := make(chan struct{})
    go func() { s.wg.Wait(); close(done) }()

    select {
    case \x3C-done:
        fmt.Println("Clean shutdown completed")
    case \x3C-time.After(timeout):
        fmt.Println("Shutdown timed out, forcing exit")
    }
}

Pattern 6: Concurrent Map

// sync.Map: optimized for read-heavy workloads with stable keys
type Cache struct {
    m sync.Map
}

func (c *Cache) Get(key string) (any, bool) { return c.m.Load(key) }
func (c *Cache) Set(key string, value any) { c.m.Store(key, value) }
func (c *Cache) GetOrSet(key string, val any) (any, bool) {
    return c.m.LoadOrStore(key, val)
}

// ShardedMap: better for write-heavy workloads
type ShardedMap struct {
    shards    []*shard
    numShards int
}

type shard struct {
    sync.RWMutex
    data map[string]any
}

func NewShardedMap(n int) *ShardedMap {
    m := &ShardedMap{shards: make([]*shard, n), numShards: n}
    for i := range m.shards {
        m.shards[i] = &shard{data: make(map[string]any)}
    }
    return m
}

func (m *ShardedMap) getShard(key string) *shard {
    h := 0
    for _, c := range key {
        h = 31*h + int(c)
    }
    return m.shards[h%m.numShards]
}

func (m *ShardedMap) Get(key string) (any, bool) {
    s := m.getShard(key)
    s.RLock()
    defer s.RUnlock()
    v, ok := s.data[key]
    return v, ok
}

func (m *ShardedMap) Set(key string, value any) {
    s := m.getShard(key)
    s.Lock()
    defer s.Unlock()
    s.data[key] = value
}

When to use which:

  • sync.Map — Few keys, many reads, keys added once and rarely deleted
  • ShardedMap — Many keys, frequent writes, need predictable performance

Select Patterns

// Timeout
select {
case v := \x3C-ch:
    fmt.Println("Received:", v)
case \x3C-time.After(time.Second):
    fmt.Println("Timeout!")
}

// Non-blocking send/receive
select {
case ch \x3C- 42:
    fmt.Println("Sent")
default:
    fmt.Println("Channel full, skipping")
}

// Priority select: check high-priority first
for {
    select {
    case msg := \x3C-highPriority:
        handle(msg)
    default:
        select {
        case msg := \x3C-highPriority:
            handle(msg)
        case msg := \x3C-lowPriority:
            handle(msg)
        }
    }
}

Race Detection

go test -race ./...     # Tests with race detector
go build -race .        # Build with race detector
go run -race main.go    # Run with race detector

Best Practices

Do:

  • Use context.Context for cancellation and deadlines on every goroutine
  • Close channels from the sender side only
  • Use errgroup for concurrent operations that return errors
  • Buffer channels when count is known upfront
  • Prefer channels over mutexes for coordination
  • Always run tests with -race

Don't:

  • Leak goroutines — every goroutine must have an exit path
  • Close a channel from the receiver — causes panic
  • Use time.Sleep for synchronization — use proper primitives
  • Ignore ctx.Done() in long-running goroutines
  • Share memory without synchronization — use channels or mutexes

NEVER Do

  • NEVER close a channel from the receiver — Only the sender should close; receivers panic on closed channels
  • NEVER send on a closed channel — Causes panic; design so sender controls close
  • NEVER use unbounded goroutine spawning — Use worker pools or semaphores for bounded concurrency
  • NEVER ignore the -race flag in testing — Data races are silent bugs that corrupt state
  • NEVER pass pointers to loop variables into goroutines — Capture the value or use index closure pattern
  • NEVER use time.Sleep as synchronization — Use channels, WaitGroups, or context
安全使用建议
This is an instruction-only skill providing Go concurrency examples; it's internally consistent and low-risk. Before running any example code locally, inspect it (the SKILL.md appears truncated in one place) and review network calls or third-party imports (e.g., http requests, golang.org/x packages). If you plan to follow the README's 'npx add' or copy steps, validate those commands — the README references a GitHub tree URL which is an unconventional usage and should be reviewed before executing.
功能分析
Type: OpenClaw Skill Name: go-concurrency-patterns Version: 1.0.0 The skill bundle provides educational content and code examples for Go concurrency patterns. All Go code examples are benign and illustrative, demonstrating standard concurrency practices. The `SKILL.md` and `README.md` contain no evidence of prompt injection, data exfiltration, malicious execution, persistence mechanisms, or other harmful behaviors. Network access in one Go example (`fetchAllURLs`) is part of a legitimate demonstration of concurrent HTTP requests, not exfiltration. Installation instructions involve copying local files or using a platform-specific `npx add` command, which are not inherently malicious.
能力评估
Purpose & Capability
Name and description (Go concurrency patterns) match the contents of SKILL.md and README: code examples and patterns for goroutines, channels, context, worker pools, pipelines, errgroup, etc. Nothing in the metadata or files asks for unrelated capabilities (no cloud credentials, no system access).
Instruction Scope
SKILL.md contains code samples and prose describing patterns; it does not instruct the agent to read arbitrary files, access secrets, or transmit data to unexpected external endpoints. Example snippets include HTTP requests as illustrative code for fetch use-cases (normal for such a tutorial) but do not direct the agent to execute network calls itself.
Install Mechanism
There is no formal install spec (instruction-only), which is low risk. The README mentions an 'npx add' command pointing at a GitHub tree URL and local copy instructions; these are only documentation and not executed by the agent. The 'npx add' usage is unconventional (pointing to a tree URL) but does not affect the skill's runtime behavior. If you plan to follow those install steps, review them before executing.
Credentials
The skill declares no required environment variables, credentials, or config paths. SKILL.md examples reference standard Go packages and context usage only. There is no disproportionate or unexplained request for secrets.
Persistence & Privilege
Skill is not always-enabled (always: false) and is user-invocable. There is no install-time code or files added by the platform and no indication the skill modifies other skills or global agent configs.
如何使用
  1. 确保已安装 OpenClaw(本地或 Docker 部署)
  2. 在对话框中输入安装命令:/install go-concurrency-patterns
  3. 安装完成后,直接呼叫该 Skill 的名称或使用 /go-concurrency-patterns 触发
  4. 根据 Skill 的参数说明提供必要输入,即可获得结构化输出
版本历史
v1.0.0
Initial release of Go concurrency patterns with practical production examples. - Introduces patterns for goroutines, channels, synchronization primitives, context management, worker pools, pipelines, and graceful shutdown in Go. - Provides quick start code and tables for choosing concurrency primitives. - Includes implementations for worker pools, fan-out/fan-in pipelines, bounded concurrency (semaphores), errgroup for error handling and cancellation, and graceful shutdown. - Aims to assist with concurrent Go application development and race condition debugging.
元数据
Slug go-concurrency-patterns
版本 1.0.0
许可证
累计安装 0
当前安装数 0
历史版本数 1
常见问题

Go Concurrency Patterns 是什么?

Production Go concurrency patterns — goroutines, channels, sync primitives, context, worker pools, pipelines, and graceful shutdown. Use when building concurrent Go applications or debugging race conditions. 它是一个面向 Claude Code / OpenClaw 的 AI Agent Skill 插件,目前累计下载 818 次。

如何安装 Go Concurrency Patterns?

在 OpenClaw 或 Claude Code 对话框中运行命令「/install go-concurrency-patterns」即可一键安装,无需额外配置。

Go Concurrency Patterns 是免费的吗?

是的,Go Concurrency Patterns 完全免费(开源免费),可自由下载、安装和使用。

Go Concurrency Patterns 支持哪些平台?

Go Concurrency Patterns 跨平台运行,可在任意部署了 OpenClaw / Claude Code 的环境中使用(cross-platform)。

谁开发了 Go Concurrency Patterns?

由 wpank(@wpank)开发并维护,当前版本 v1.0.0。

💬 留言讨论