goroutine-patterns

Implement Go concurrency patterns for efficient parallel processing.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "goroutine-patterns" with this command: npx skills add armanzeroeight/fastagent-plugins/armanzeroeight-fastagent-plugins-goroutine-patterns

Goroutine Patterns

Implement Go concurrency patterns for efficient parallel processing.

Quick Start

Basic goroutine:

go func() { // Runs concurrently }()

With channel:

ch := make(chan int) go func() { ch <- 42 }() result := <-ch

Instructions

Step 1: Choose Concurrency Pattern

Simple parallel execution:

var wg sync.WaitGroup

for i := 0; i < 10; i++ { wg.Add(1) go func(id int) { defer wg.Done() process(id) }(i) }

wg.Wait()

Worker pool:

jobs := make(chan Job, 100) results := make(chan Result, 100)

// Start workers for w := 0; w < numWorkers; w++ { go worker(jobs, results) }

// Send jobs for _, job := range allJobs { jobs <- job } close(jobs)

// Collect results for range allJobs { result := <-results handleResult(result) }

Pipeline:

// Stage 1: Generate gen := func() <-chan int { out := make(chan int) go func() { defer close(out) for i := 0; i < 10; i++ { out <- i } }() return out }

// Stage 2: Process process := func(in <-chan int) <-chan int { out := make(chan int) go func() { defer close(out) for n := range in { out <- n * 2 } }() return out }

// Use pipeline for result := range process(gen()) { fmt.Println(result) }

Step 2: Implement Channel Communication

Unbuffered channel (synchronous):

ch := make(chan int)

go func() { ch <- 42 // Blocks until received }()

value := <-ch // Blocks until sent

Buffered channel (asynchronous):

ch := make(chan int, 10) // Buffer of 10

ch <- 1 // Doesn't block until buffer full ch <- 2

value := <-ch // Doesn't block if buffer has data

Select for multiple channels:

select { case msg := <-ch1: fmt.Println("Received from ch1:", msg) case msg := <-ch2: fmt.Println("Received from ch2:", msg) case <-time.After(time.Second): fmt.Println("Timeout") }

Step 3: Use Synchronization Primitives

Mutex for shared state:

type SafeCounter struct { mu sync.Mutex count int }

func (c *SafeCounter) Inc() { c.mu.Lock() defer c.mu.Unlock() c.count++ }

func (c *SafeCounter) Value() int { c.mu.Lock() defer c.mu.Unlock() return c.count }

RWMutex for read-heavy workloads:

type Cache struct { mu sync.RWMutex items map[string]string }

func (c *Cache) Get(key string) (string, bool) { c.mu.RLock() defer c.mu.RUnlock() val, ok := c.items[key] return val, ok }

func (c *Cache) Set(key, value string) { c.mu.Lock() defer c.mu.Unlock() c.items[key] = value }

WaitGroup for goroutine coordination:

var wg sync.WaitGroup

for i := 0; i < 5; i++ { wg.Add(1) go func(id int) { defer wg.Done() doWork(id) }(i) }

wg.Wait() // Wait for all goroutines

Step 4: Implement Context for Cancellation

Basic context usage:

ctx, cancel := context.WithCancel(context.Background()) defer cancel()

go func() { for { select { case <-ctx.Done(): return // Exit when cancelled default: doWork() } } }()

// Cancel when done cancel()

With timeout:

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

result, err := doWorkWithContext(ctx) if err == context.DeadlineExceeded { fmt.Println("Operation timed out") }

Propagate context:

func ProcessRequest(ctx context.Context, req Request) error { // Pass context to all operations data, err := fetchData(ctx, req.ID) if err != nil { return err }

return saveData(ctx, data)

}

Common Patterns

Fan-Out/Fan-In

func fanOut(in <-chan int, n int) []<-chan int { outs := make([]<-chan int, n) for i := 0; i < n; i++ { outs[i] = process(in) } return outs }

func fanIn(channels ...<-chan int) <-chan int { out := make(chan int) var wg sync.WaitGroup

for _, ch := range channels {
    wg.Add(1)
    go func(c &#x3C;-chan int) {
        defer wg.Done()
        for n := range c {
            out &#x3C;- n
        }
    }(ch)
}

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

return out

}

Rate Limiting

func rateLimiter(rate time.Duration) <-chan time.Time { return time.Tick(rate) }

limiter := rateLimiter(time.Second / 10) // 10 per second

for range limiter { go processItem() }

Timeout Pattern

func doWithTimeout(timeout time.Duration) error { done := make(chan error, 1)

go func() {
    done &#x3C;- doWork()
}()

select {
case err := &#x3C;-done:
    return err
case &#x3C;-time.After(timeout):
    return errors.New("timeout")
}

}

Error Group

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

func processAll(items []Item) error { g := new(errgroup.Group)

for _, item := range items {
    item := item // Capture for goroutine
    g.Go(func() error {
        return process(item)
    })
}

return g.Wait() // Returns first error

}

Advanced

For detailed patterns:

  • Channels - Channel patterns and best practices

  • Sync - Synchronization primitives

  • Context - Context usage and propagation

Troubleshooting

Goroutine leaks:

  • Always ensure goroutines can exit

  • Use context for cancellation

  • Close channels when done

Deadlocks:

  • Avoid circular channel dependencies

  • Don't send on unbuffered channel without receiver

  • Use select with timeout

Race conditions:

  • Use go run -race to detect

  • Protect shared state with mutexes

  • Prefer channels for communication

Performance issues:

  • Don't create too many goroutines

  • Use worker pools for bounded concurrency

  • Profile with pprof

Best Practices

  • Don't communicate by sharing memory; share memory by communicating

  • Always handle goroutine cleanup: Use context, defer, or done channels

  • Avoid goroutine leaks: Ensure all goroutines can exit

  • Use buffered channels carefully: Can hide synchronization issues

  • Prefer sync.WaitGroup: For waiting on multiple goroutines

  • Pass context: Propagate cancellation through call stack

  • Close channels from sender: Never close from receiver

  • Check channel closure: Use val, ok := <-ch

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Automation

gcp-cost-optimizer

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

schema-designer

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

terraform-state-manager

No summary provided by upstream source.

Repository SourceNeeds Review