Goroutines Flashcards
(10 cards)
Goroutine Basics
Definition:
Lightweight thread managed by the Go runtime (not OS threads).
Starts with:
go func() { fmt.Println("Running concurrently!") }()
Key Traits:
* ~2KB stack (grows dynamically)
* Scheduled by Go runtime (M:N threading)
* Cheap to create (thousands are practical)
Goroutine vs Thread
Feature Goroutine OS Thread
Memory ~2KB initial ~1MB+ (default)
Creation Fast (runtime) Slow (OS)
Switch Runtime-managed Kernel-managed
Cost Thousands feasible Hundreds limited
Synchronization (WaitGroup)
Block until done:
var wg sync.WaitGroup wg.Add(1) // Set counter go func() { defer wg.Done() // Decrement counter // Work... }() wg.Wait() // Blocks until counter=0
Use Case: Wait for N goroutines to complete.
Channels (Basic)
Create:
ch := make(chan int) // Unbuffered chBuffered := make(chan string, 3) // Buffered
Send/Receive:
ch <- 42 // Send val := <-ch // Receive (blocks) val, ok := <-ch // Check if channel closed
Select Statement
Multiplex channels:
select { case msg := <-ch1: fmt.Println(msg) case ch2 <- time.Now(): // Sent time case <-time.After(1 * time.Second): fmt.Println("Timeout") default: // Non-blocking fallthrough }
Rules:
Random selection if multiple ready
default prevents blocking
Worker Pool Pattern
jobs := make(chan int, 100) results := make(chan int, 100) // Start 3 workers for w := 1; w <= 3; w++ { go func(id int) { for job := range jobs { results <- job * 2 } }(w) } // Send jobs for j := 1; j <= 5; j++ { jobs <- j } close(jobs) // Collect results for r := 1; r <= 5; r++ { fmt.Println(<-results) }
Common Pitfalls
Leaking Goroutines:
go func() { for { /* runs forever */ } }() // No way to stop! Fix: Use context or done channels.
Race Conditions:
var counter int go func() { counter++ }() go func() { counter++ }() // Data race!
Fix: Use sync.Mutex or channels.
Context + Goroutines
Graceful shutdown:
ctx, cancel := context.WithCancel(context.Background()) go func() { <-ctx.Done() // Triggered on cancel() fmt.Println("Stopped cleanly") }() cancel() // Signal cancellation
Benchmarking Goroutines
Test creation cost:
func BenchmarkGoroutine(b *testing.B) { for i := 0; i < b.N; i++ { go func() {}() // Measure overhead } }
Typical result: ~300ns per goroutine on modern hardware
Golden Rules
- Don’t ignore goroutine errors (use error channels)
- Always clean up resources (avoid leaks)
- Prefer channels over shared memory
- Use sync.WaitGroup for coordination
- Monitor goroutine counts in production