{
  "schemaVersion": "1.0",
  "item": {
    "slug": "go-concurrency-patterns",
    "name": "Go Concurrency Patterns",
    "source": "tencent",
    "type": "skill",
    "category": "开发工具",
    "sourceUrl": "https://clawhub.ai/wpank/go-concurrency-patterns",
    "canonicalUrl": "https://clawhub.ai/wpank/go-concurrency-patterns",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/go-concurrency-patterns",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=go-concurrency-patterns",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "README.md",
      "SKILL.md"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Then review README.md for any prerequisites, environment setup, or post-install checks. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Then review README.md for any prerequisites, environment setup, or post-install checks. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "slug": "go-concurrency-patterns",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-05-03T19:30:16.027Z",
      "expiresAt": "2026-05-10T19:30:16.027Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=go-concurrency-patterns",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=go-concurrency-patterns",
        "contentDisposition": "attachment; filename=\"go-concurrency-patterns-1.0.0.zip\"",
        "redirectLocation": null,
        "bodySnippet": null,
        "slug": "go-concurrency-patterns"
      },
      "scope": "item",
      "summary": "Item download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this item.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/go-concurrency-patterns"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/go-concurrency-patterns",
    "agentPageUrl": "https://openagent3.xyz/skills/go-concurrency-patterns/agent",
    "manifestUrl": "https://openagent3.xyz/skills/go-concurrency-patterns/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/go-concurrency-patterns/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Then review README.md for any prerequisites, environment setup, or post-install checks. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Then review README.md for any prerequisites, environment setup, or post-install checks. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "Go Concurrency Patterns",
        "body": "Production patterns for Go concurrency including goroutines, channels, synchronization primitives, and context management."
      },
      {
        "title": "When to Use",
        "body": "Building concurrent Go applications\nImplementing worker pools and pipelines\nManaging goroutine lifecycles and cancellation\nDebugging race conditions\nImplementing graceful shutdown"
      },
      {
        "title": "Concurrency Primitives",
        "body": "PrimitivePurposeWhen to UsegoroutineLightweight concurrent executionAny concurrent workchannelCommunication between goroutinesPassing data, signalingselectMultiplex channel operationsWaiting on multiple channelssync.MutexMutual exclusionProtecting shared statesync.WaitGroupWait for goroutines to completeCoordinating goroutine completioncontext.ContextCancellation and deadlinesRequest-scoped lifecycle managementerrgroup.GroupConcurrent tasks with errorsParallel work that can fail\n\nGo Concurrency Mantra: Don't communicate by sharing memory; share memory by communicating."
      },
      {
        "title": "Quick Start",
        "body": "func main() {\n    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n    defer cancel()\n\n    results := make(chan string, 10)\n    var wg sync.WaitGroup\n\n    for i := 0; i < 3; i++ {\n        wg.Add(1)\n        go func(id int) {\n            defer wg.Done()\n            select {\n            case <-ctx.Done():\n                return\n            case results <- fmt.Sprintf(\"Worker %d done\", id):\n            }\n        }(i)\n    }\n\n    go func() { wg.Wait(); close(results) }()\n\n    for result := range results {\n        fmt.Println(result)\n    }\n}"
      },
      {
        "title": "Pattern 1: Worker Pool",
        "body": "type Job struct {\n    ID   int\n    Data string\n}\n\ntype Result struct {\n    JobID  int\n    Output string\n    Err    error\n}\n\nfunc WorkerPool(ctx context.Context, numWorkers int, jobs <-chan Job) <-chan Result {\n    results := make(chan Result)\n    var wg sync.WaitGroup\n\n    for i := 0; i < numWorkers; i++ {\n        wg.Add(1)\n        go func() {\n            defer wg.Done()\n            for job := range jobs {\n                select {\n                case <-ctx.Done():\n                    return\n                default:\n                    results <- Result{\n                        JobID:  job.ID,\n                        Output: fmt.Sprintf(\"Processed: %s\", job.Data),\n                    }\n                }\n            }\n        }()\n    }\n\n    go func() { wg.Wait(); close(results) }()\n    return results\n}\n\n// Usage\nfunc main() {\n    ctx, cancel := context.WithCancel(context.Background())\n    defer cancel()\n\n    jobs := make(chan Job, 100)\n    go func() {\n        for i := 0; i < 50; i++ {\n            jobs <- Job{ID: i, Data: fmt.Sprintf(\"job-%d\", i)}\n        }\n        close(jobs)\n    }()\n\n    for result := range WorkerPool(ctx, 5, jobs) {\n        fmt.Printf(\"Result: %+v\\n\", result)\n    }\n}"
      },
      {
        "title": "Pattern 2: Fan-Out / Fan-In Pipeline",
        "body": "// Stage 1: Generate values\nfunc generate(ctx context.Context, nums ...int) <-chan int {\n    out := make(chan int)\n    go func() {\n        defer close(out)\n        for _, n := range nums {\n            select {\n            case <-ctx.Done(): return\n            case out <- n:\n            }\n        }\n    }()\n    return out\n}\n\n// Stage 2: Transform (run multiple instances for fan-out)\nfunc square(ctx context.Context, in <-chan int) <-chan int {\n    out := make(chan int)\n    go func() {\n        defer close(out)\n        for n := range in {\n            select {\n            case <-ctx.Done(): return\n            case out <- n * n:\n            }\n        }\n    }()\n    return out\n}\n\n// Fan-in: Merge multiple channels into one\nfunc merge(ctx context.Context, channels ...<-chan int) <-chan int {\n    var wg sync.WaitGroup\n    out := make(chan int)\n\n    wg.Add(len(channels))\n    for _, ch := range channels {\n        go func(c <-chan int) {\n            defer wg.Done()\n            for n := range c {\n                select {\n                case <-ctx.Done(): return\n                case out <- n:\n                }\n            }\n        }(ch)\n    }\n\n    go func() { wg.Wait(); close(out) }()\n    return out\n}\n\n// Usage: fan out to 3 squarers, fan in results\nfunc main() {\n    ctx, cancel := context.WithCancel(context.Background())\n    defer cancel()\n\n    in := generate(ctx, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)\n    c1 := square(ctx, in)\n    c2 := square(ctx, in)\n    c3 := square(ctx, in)\n\n    for result := range merge(ctx, c1, c2, c3) {\n        fmt.Println(result)\n    }\n}"
      },
      {
        "title": "Pattern 3: errgroup with Cancellation",
        "body": "import \"golang.org/x/sync/errgroup\"\n\nfunc fetchAllURLs(ctx context.Context, urls []string) ([]string, error) {\n    g, ctx := errgroup.WithContext(ctx)\n    results := make([]string, len(urls))\n\n    for i, url := range urls {\n        i, url := i, url\n        g.Go(func() error {\n            req, err := http.NewRequestWithContext(ctx, \"GET\", url, nil)\n            if err != nil {\n                return fmt.Errorf(\"creating request for %s: %w\", url, err)\n            }\n            resp, err := http.DefaultClient.Do(req)\n            if err != nil {\n                return fmt.Errorf(\"fetching %s: %w\", url, err)\n            }\n            defer resp.Body.Close()\n            results[i] = fmt.Sprintf(\"%s: %d\", url, resp.StatusCode)\n            return nil\n        })\n    }\n\n    if err := g.Wait(); err != nil {\n        return nil, err // First error cancels all others via ctx\n    }\n    return results, nil\n}\n\n// With concurrency limit\nfunc fetchWithLimit(ctx context.Context, urls []string) ([]string, error) {\n    g, ctx := errgroup.WithContext(ctx)\n    g.SetLimit(10) // Max concurrent goroutines\n    results := make([]string, len(urls))\n\n    for i, url := range urls {\n        i, url := i, url\n        g.Go(func() error {\n            result, err := fetchURL(ctx, url)\n            if err != nil { return err }\n            results[i] = result\n            return nil\n        })\n    }\n\n    return results, g.Wait()\n}"
      },
      {
        "title": "Pattern 4: Bounded Concurrency (Semaphore)",
        "body": "import \"golang.org/x/sync/semaphore\"\n\ntype RateLimitedWorker struct {\n    sem *semaphore.Weighted\n}\n\nfunc NewRateLimitedWorker(maxConcurrent int64) *RateLimitedWorker {\n    return &RateLimitedWorker{sem: semaphore.NewWeighted(maxConcurrent)}\n}\n\nfunc (w *RateLimitedWorker) Do(ctx context.Context, tasks []func() error) []error {\n    var (\n        wg     sync.WaitGroup\n        mu     sync.Mutex\n        errors []error\n    )\n\n    for _, task := range tasks {\n        if err := w.sem.Acquire(ctx, 1); err != nil {\n            return []error{err}\n        }\n        wg.Add(1)\n        go func(t func() error) {\n            defer wg.Done()\n            defer w.sem.Release(1)\n            if err := t(); err != nil {\n                mu.Lock()\n                errors = append(errors, err)\n                mu.Unlock()\n            }\n        }(task)\n    }\n\n    wg.Wait()\n    return errors\n}\n\n// Simpler alternative: channel-based semaphore\ntype Semaphore chan struct{}\n\nfunc NewSemaphore(n int) Semaphore       { return make(chan struct{}, n) }\nfunc (s Semaphore) Acquire()             { s <- struct{}{} }\nfunc (s Semaphore) Release()             { <-s }"
      },
      {
        "title": "Pattern 5: Graceful Shutdown",
        "body": "func main() {\n    ctx, cancel := context.WithCancel(context.Background())\n\n    sigCh := make(chan os.Signal, 1)\n    signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)\n\n    server := NewServer()\n    server.Start(ctx)\n\n    sig := <-sigCh\n    fmt.Printf(\"Received signal: %v\\n\", sig)\n    cancel() // Cancel context to stop all workers\n\n    server.Shutdown(5 * time.Second)\n}\n\ntype Server struct {\n    wg sync.WaitGroup\n}\n\nfunc (s *Server) Start(ctx context.Context) {\n    for i := 0; i < 5; i++ {\n        s.wg.Add(1)\n        go s.worker(ctx, i)\n    }\n}\n\nfunc (s *Server) worker(ctx context.Context, id int) {\n    defer s.wg.Done()\n    ticker := time.NewTicker(time.Second)\n    defer ticker.Stop()\n\n    for {\n        select {\n        case <-ctx.Done():\n            fmt.Printf(\"Worker %d cleaning up...\\n\", id)\n            return\n        case <-ticker.C:\n            fmt.Printf(\"Worker %d working...\\n\", id)\n        }\n    }\n}\n\nfunc (s *Server) Shutdown(timeout time.Duration) {\n    done := make(chan struct{})\n    go func() { s.wg.Wait(); close(done) }()\n\n    select {\n    case <-done:\n        fmt.Println(\"Clean shutdown completed\")\n    case <-time.After(timeout):\n        fmt.Println(\"Shutdown timed out, forcing exit\")\n    }\n}"
      },
      {
        "title": "Pattern 6: Concurrent Map",
        "body": "// sync.Map: optimized for read-heavy workloads with stable keys\ntype Cache struct {\n    m sync.Map\n}\n\nfunc (c *Cache) Get(key string) (any, bool) { return c.m.Load(key) }\nfunc (c *Cache) Set(key string, value any) { c.m.Store(key, value) }\nfunc (c *Cache) GetOrSet(key string, val any) (any, bool) {\n    return c.m.LoadOrStore(key, val)\n}\n\n// ShardedMap: better for write-heavy workloads\ntype ShardedMap struct {\n    shards    []*shard\n    numShards int\n}\n\ntype shard struct {\n    sync.RWMutex\n    data map[string]any\n}\n\nfunc NewShardedMap(n int) *ShardedMap {\n    m := &ShardedMap{shards: make([]*shard, n), numShards: n}\n    for i := range m.shards {\n        m.shards[i] = &shard{data: make(map[string]any)}\n    }\n    return m\n}\n\nfunc (m *ShardedMap) getShard(key string) *shard {\n    h := 0\n    for _, c := range key {\n        h = 31*h + int(c)\n    }\n    return m.shards[h%m.numShards]\n}\n\nfunc (m *ShardedMap) Get(key string) (any, bool) {\n    s := m.getShard(key)\n    s.RLock()\n    defer s.RUnlock()\n    v, ok := s.data[key]\n    return v, ok\n}\n\nfunc (m *ShardedMap) Set(key string, value any) {\n    s := m.getShard(key)\n    s.Lock()\n    defer s.Unlock()\n    s.data[key] = value\n}\n\nWhen to use which:\n\nsync.Map — Few keys, many reads, keys added once and rarely deleted\nShardedMap — Many keys, frequent writes, need predictable performance"
      },
      {
        "title": "Select Patterns",
        "body": "// Timeout\nselect {\ncase v := <-ch:\n    fmt.Println(\"Received:\", v)\ncase <-time.After(time.Second):\n    fmt.Println(\"Timeout!\")\n}\n\n// Non-blocking send/receive\nselect {\ncase ch <- 42:\n    fmt.Println(\"Sent\")\ndefault:\n    fmt.Println(\"Channel full, skipping\")\n}\n\n// Priority select: check high-priority first\nfor {\n    select {\n    case msg := <-highPriority:\n        handle(msg)\n    default:\n        select {\n        case msg := <-highPriority:\n            handle(msg)\n        case msg := <-lowPriority:\n            handle(msg)\n        }\n    }\n}"
      },
      {
        "title": "Race Detection",
        "body": "go test -race ./...     # Tests with race detector\ngo build -race .        # Build with race detector\ngo run -race main.go    # Run with race detector"
      },
      {
        "title": "Best Practices",
        "body": "Do:\n\nUse context.Context for cancellation and deadlines on every goroutine\nClose channels from the sender side only\nUse errgroup for concurrent operations that return errors\nBuffer channels when count is known upfront\nPrefer channels over mutexes for coordination\nAlways run tests with -race\n\nDon't:\n\nLeak goroutines — every goroutine must have an exit path\nClose a channel from the receiver — causes panic\nUse time.Sleep for synchronization — use proper primitives\nIgnore ctx.Done() in long-running goroutines\nShare memory without synchronization — use channels or mutexes"
      },
      {
        "title": "NEVER Do",
        "body": "NEVER close a channel from the receiver — Only the sender should close; receivers panic on closed channels\nNEVER send on a closed channel — Causes panic; design so sender controls close\nNEVER use unbounded goroutine spawning — Use worker pools or semaphores for bounded concurrency\nNEVER ignore the -race flag in testing — Data races are silent bugs that corrupt state\nNEVER pass pointers to loop variables into goroutines — Capture the value or use index closure pattern\nNEVER use time.Sleep as synchronization — Use channels, WaitGroups, or context"
      }
    ],
    "body": "Go Concurrency Patterns\n\nProduction patterns for Go concurrency including goroutines, channels, synchronization primitives, and context management.\n\nWhen to Use\nBuilding concurrent Go applications\nImplementing worker pools and pipelines\nManaging goroutine lifecycles and cancellation\nDebugging race conditions\nImplementing graceful shutdown\nConcurrency Primitives\nPrimitive\tPurpose\tWhen to Use\ngoroutine\tLightweight concurrent execution\tAny concurrent work\nchannel\tCommunication between goroutines\tPassing data, signaling\nselect\tMultiplex channel operations\tWaiting on multiple channels\nsync.Mutex\tMutual exclusion\tProtecting shared state\nsync.WaitGroup\tWait for goroutines to complete\tCoordinating goroutine completion\ncontext.Context\tCancellation and deadlines\tRequest-scoped lifecycle management\nerrgroup.Group\tConcurrent tasks with errors\tParallel work that can fail\n\nGo Concurrency Mantra: Don't communicate by sharing memory; share memory by communicating.\n\nQuick Start\nfunc main() {\n    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n    defer cancel()\n\n    results := make(chan string, 10)\n    var wg sync.WaitGroup\n\n    for i := 0; i < 3; i++ {\n        wg.Add(1)\n        go func(id int) {\n            defer wg.Done()\n            select {\n            case <-ctx.Done():\n                return\n            case results <- fmt.Sprintf(\"Worker %d done\", id):\n            }\n        }(i)\n    }\n\n    go func() { wg.Wait(); close(results) }()\n\n    for result := range results {\n        fmt.Println(result)\n    }\n}\n\nPattern 1: Worker Pool\ntype Job struct {\n    ID   int\n    Data string\n}\n\ntype Result struct {\n    JobID  int\n    Output string\n    Err    error\n}\n\nfunc WorkerPool(ctx context.Context, numWorkers int, jobs <-chan Job) <-chan Result {\n    results := make(chan Result)\n    var wg sync.WaitGroup\n\n    for i := 0; i < numWorkers; i++ {\n        wg.Add(1)\n        go func() {\n            defer wg.Done()\n            for job := range jobs {\n                select {\n                case <-ctx.Done():\n                    return\n                default:\n                    results <- Result{\n                        JobID:  job.ID,\n                        Output: fmt.Sprintf(\"Processed: %s\", job.Data),\n                    }\n                }\n            }\n        }()\n    }\n\n    go func() { wg.Wait(); close(results) }()\n    return results\n}\n\n// Usage\nfunc main() {\n    ctx, cancel := context.WithCancel(context.Background())\n    defer cancel()\n\n    jobs := make(chan Job, 100)\n    go func() {\n        for i := 0; i < 50; i++ {\n            jobs <- Job{ID: i, Data: fmt.Sprintf(\"job-%d\", i)}\n        }\n        close(jobs)\n    }()\n\n    for result := range WorkerPool(ctx, 5, jobs) {\n        fmt.Printf(\"Result: %+v\\n\", result)\n    }\n}\n\nPattern 2: Fan-Out / Fan-In Pipeline\n// Stage 1: Generate values\nfunc generate(ctx context.Context, nums ...int) <-chan int {\n    out := make(chan int)\n    go func() {\n        defer close(out)\n        for _, n := range nums {\n            select {\n            case <-ctx.Done(): return\n            case out <- n:\n            }\n        }\n    }()\n    return out\n}\n\n// Stage 2: Transform (run multiple instances for fan-out)\nfunc square(ctx context.Context, in <-chan int) <-chan int {\n    out := make(chan int)\n    go func() {\n        defer close(out)\n        for n := range in {\n            select {\n            case <-ctx.Done(): return\n            case out <- n * n:\n            }\n        }\n    }()\n    return out\n}\n\n// Fan-in: Merge multiple channels into one\nfunc merge(ctx context.Context, channels ...<-chan int) <-chan int {\n    var wg sync.WaitGroup\n    out := make(chan int)\n\n    wg.Add(len(channels))\n    for _, ch := range channels {\n        go func(c <-chan int) {\n            defer wg.Done()\n            for n := range c {\n                select {\n                case <-ctx.Done(): return\n                case out <- n:\n                }\n            }\n        }(ch)\n    }\n\n    go func() { wg.Wait(); close(out) }()\n    return out\n}\n\n// Usage: fan out to 3 squarers, fan in results\nfunc main() {\n    ctx, cancel := context.WithCancel(context.Background())\n    defer cancel()\n\n    in := generate(ctx, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)\n    c1 := square(ctx, in)\n    c2 := square(ctx, in)\n    c3 := square(ctx, in)\n\n    for result := range merge(ctx, c1, c2, c3) {\n        fmt.Println(result)\n    }\n}\n\nPattern 3: errgroup with Cancellation\nimport \"golang.org/x/sync/errgroup\"\n\nfunc fetchAllURLs(ctx context.Context, urls []string) ([]string, error) {\n    g, ctx := errgroup.WithContext(ctx)\n    results := make([]string, len(urls))\n\n    for i, url := range urls {\n        i, url := i, url\n        g.Go(func() error {\n            req, err := http.NewRequestWithContext(ctx, \"GET\", url, nil)\n            if err != nil {\n                return fmt.Errorf(\"creating request for %s: %w\", url, err)\n            }\n            resp, err := http.DefaultClient.Do(req)\n            if err != nil {\n                return fmt.Errorf(\"fetching %s: %w\", url, err)\n            }\n            defer resp.Body.Close()\n            results[i] = fmt.Sprintf(\"%s: %d\", url, resp.StatusCode)\n            return nil\n        })\n    }\n\n    if err := g.Wait(); err != nil {\n        return nil, err // First error cancels all others via ctx\n    }\n    return results, nil\n}\n\n// With concurrency limit\nfunc fetchWithLimit(ctx context.Context, urls []string) ([]string, error) {\n    g, ctx := errgroup.WithContext(ctx)\n    g.SetLimit(10) // Max concurrent goroutines\n    results := make([]string, len(urls))\n\n    for i, url := range urls {\n        i, url := i, url\n        g.Go(func() error {\n            result, err := fetchURL(ctx, url)\n            if err != nil { return err }\n            results[i] = result\n            return nil\n        })\n    }\n\n    return results, g.Wait()\n}\n\nPattern 4: Bounded Concurrency (Semaphore)\nimport \"golang.org/x/sync/semaphore\"\n\ntype RateLimitedWorker struct {\n    sem *semaphore.Weighted\n}\n\nfunc NewRateLimitedWorker(maxConcurrent int64) *RateLimitedWorker {\n    return &RateLimitedWorker{sem: semaphore.NewWeighted(maxConcurrent)}\n}\n\nfunc (w *RateLimitedWorker) Do(ctx context.Context, tasks []func() error) []error {\n    var (\n        wg     sync.WaitGroup\n        mu     sync.Mutex\n        errors []error\n    )\n\n    for _, task := range tasks {\n        if err := w.sem.Acquire(ctx, 1); err != nil {\n            return []error{err}\n        }\n        wg.Add(1)\n        go func(t func() error) {\n            defer wg.Done()\n            defer w.sem.Release(1)\n            if err := t(); err != nil {\n                mu.Lock()\n                errors = append(errors, err)\n                mu.Unlock()\n            }\n        }(task)\n    }\n\n    wg.Wait()\n    return errors\n}\n\n// Simpler alternative: channel-based semaphore\ntype Semaphore chan struct{}\n\nfunc NewSemaphore(n int) Semaphore       { return make(chan struct{}, n) }\nfunc (s Semaphore) Acquire()             { s <- struct{}{} }\nfunc (s Semaphore) Release()             { <-s }\n\nPattern 5: Graceful Shutdown\nfunc main() {\n    ctx, cancel := context.WithCancel(context.Background())\n\n    sigCh := make(chan os.Signal, 1)\n    signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)\n\n    server := NewServer()\n    server.Start(ctx)\n\n    sig := <-sigCh\n    fmt.Printf(\"Received signal: %v\\n\", sig)\n    cancel() // Cancel context to stop all workers\n\n    server.Shutdown(5 * time.Second)\n}\n\ntype Server struct {\n    wg sync.WaitGroup\n}\n\nfunc (s *Server) Start(ctx context.Context) {\n    for i := 0; i < 5; i++ {\n        s.wg.Add(1)\n        go s.worker(ctx, i)\n    }\n}\n\nfunc (s *Server) worker(ctx context.Context, id int) {\n    defer s.wg.Done()\n    ticker := time.NewTicker(time.Second)\n    defer ticker.Stop()\n\n    for {\n        select {\n        case <-ctx.Done():\n            fmt.Printf(\"Worker %d cleaning up...\\n\", id)\n            return\n        case <-ticker.C:\n            fmt.Printf(\"Worker %d working...\\n\", id)\n        }\n    }\n}\n\nfunc (s *Server) Shutdown(timeout time.Duration) {\n    done := make(chan struct{})\n    go func() { s.wg.Wait(); close(done) }()\n\n    select {\n    case <-done:\n        fmt.Println(\"Clean shutdown completed\")\n    case <-time.After(timeout):\n        fmt.Println(\"Shutdown timed out, forcing exit\")\n    }\n}\n\nPattern 6: Concurrent Map\n// sync.Map: optimized for read-heavy workloads with stable keys\ntype Cache struct {\n    m sync.Map\n}\n\nfunc (c *Cache) Get(key string) (any, bool) { return c.m.Load(key) }\nfunc (c *Cache) Set(key string, value any) { c.m.Store(key, value) }\nfunc (c *Cache) GetOrSet(key string, val any) (any, bool) {\n    return c.m.LoadOrStore(key, val)\n}\n\n// ShardedMap: better for write-heavy workloads\ntype ShardedMap struct {\n    shards    []*shard\n    numShards int\n}\n\ntype shard struct {\n    sync.RWMutex\n    data map[string]any\n}\n\nfunc NewShardedMap(n int) *ShardedMap {\n    m := &ShardedMap{shards: make([]*shard, n), numShards: n}\n    for i := range m.shards {\n        m.shards[i] = &shard{data: make(map[string]any)}\n    }\n    return m\n}\n\nfunc (m *ShardedMap) getShard(key string) *shard {\n    h := 0\n    for _, c := range key {\n        h = 31*h + int(c)\n    }\n    return m.shards[h%m.numShards]\n}\n\nfunc (m *ShardedMap) Get(key string) (any, bool) {\n    s := m.getShard(key)\n    s.RLock()\n    defer s.RUnlock()\n    v, ok := s.data[key]\n    return v, ok\n}\n\nfunc (m *ShardedMap) Set(key string, value any) {\n    s := m.getShard(key)\n    s.Lock()\n    defer s.Unlock()\n    s.data[key] = value\n}\n\n\nWhen to use which:\n\nsync.Map — Few keys, many reads, keys added once and rarely deleted\nShardedMap — Many keys, frequent writes, need predictable performance\nSelect Patterns\n// Timeout\nselect {\ncase v := <-ch:\n    fmt.Println(\"Received:\", v)\ncase <-time.After(time.Second):\n    fmt.Println(\"Timeout!\")\n}\n\n// Non-blocking send/receive\nselect {\ncase ch <- 42:\n    fmt.Println(\"Sent\")\ndefault:\n    fmt.Println(\"Channel full, skipping\")\n}\n\n// Priority select: check high-priority first\nfor {\n    select {\n    case msg := <-highPriority:\n        handle(msg)\n    default:\n        select {\n        case msg := <-highPriority:\n            handle(msg)\n        case msg := <-lowPriority:\n            handle(msg)\n        }\n    }\n}\n\nRace Detection\ngo test -race ./...     # Tests with race detector\ngo build -race .        # Build with race detector\ngo run -race main.go    # Run with race detector\n\nBest Practices\n\nDo:\n\nUse context.Context for cancellation and deadlines on every goroutine\nClose channels from the sender side only\nUse errgroup for concurrent operations that return errors\nBuffer channels when count is known upfront\nPrefer channels over mutexes for coordination\nAlways run tests with -race\n\nDon't:\n\nLeak goroutines — every goroutine must have an exit path\nClose a channel from the receiver — causes panic\nUse time.Sleep for synchronization — use proper primitives\nIgnore ctx.Done() in long-running goroutines\nShare memory without synchronization — use channels or mutexes\nNEVER Do\nNEVER close a channel from the receiver — Only the sender should close; receivers panic on closed channels\nNEVER send on a closed channel — Causes panic; design so sender controls close\nNEVER use unbounded goroutine spawning — Use worker pools or semaphores for bounded concurrency\nNEVER ignore the -race flag in testing — Data races are silent bugs that corrupt state\nNEVER pass pointers to loop variables into goroutines — Capture the value or use index closure pattern\nNEVER use time.Sleep as synchronization — Use channels, WaitGroups, or context"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/wpank/go-concurrency-patterns",
    "publisherUrl": "https://clawhub.ai/wpank/go-concurrency-patterns",
    "owner": "wpank",
    "version": "1.0.0",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/go-concurrency-patterns",
    "downloadUrl": "https://openagent3.xyz/downloads/go-concurrency-patterns",
    "agentUrl": "https://openagent3.xyz/skills/go-concurrency-patterns/agent",
    "manifestUrl": "https://openagent3.xyz/skills/go-concurrency-patterns/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/go-concurrency-patterns/agent.md"
  }
}