Concurrency and Goroutines
Go's concurrency model is one of its most distinctive features, built around the concept of goroutines and channels. Unlike JavaScript's single-threaded event loop or C++'s complex threading model, Go provides a simple yet powerful approach to concurrent programming with the motto "Don't communicate by sharing memory; share memory by communicating."
Concurrency vs. Parallelism
Concurrency is the ability to handle multiple tasks by interleaving their execution, while parallelism is the ability to execute multiple tasks simultaneously on different CPU cores.
- JavaScript: Primarily concurrent through the event loop, with limited parallelism through Web Workers
- Go: Both concurrent (goroutines) and parallel (can utilize multiple CPU cores)
Goroutines: Lightweight Threads
Goroutines are Go's way of handling concurrent operations. They are lightweight threads managed by the Go runtime, not the operating system.
Goroutine Lifecycle
Creating Goroutines
Goroutines are created using the go
keyword followed by a function call:
Goroutine Synchronization
Unlike JavaScript's Promise-based synchronization, Go uses channels and sync primitives:
Channels: Communication Between Goroutines
Channels are Go's primary mechanism for communication between goroutines. They provide a safe way to share data without explicit locking.
Basic Channel Operations
Buffered vs Unbuffered Channels
Select Statement
The select
statement allows goroutines to wait on multiple channel operations:
Common Concurrency Patterns
Worker Pool Pattern
Pipeline Pattern
Goroutine Best Practices
1. Always Handle Goroutine Lifecycle
2. Avoid Goroutine Leaks
Performance Considerations
Goroutine vs Thread Comparison
Aspect | Goroutines | OS Threads |
---|---|---|
Memory | ~2KB stack | ~1MB stack |
Creation | ~0.3μs | ~17μs |
Context Switch | ~0.2μs | ~1.7μs |
Concurrency | Millions | Thousands |
When to Use Goroutines
- I/O-bound operations: Network requests, file operations
- CPU-bound operations: Mathematical computations (with proper coordination)
- Event handling: Processing multiple events concurrently
- Background tasks: Cleanup, monitoring, logging
Practice Questions:
- What is the difference between concurrency and parallelism in Go?
- How do goroutines differ from OS threads in terms of resource usage?
- Explain the difference between buffered and unbuffered channels.
- When would you use a
select
statement instead of a simple channel receive? - What are some common patterns for preventing goroutine leaks?
Project Idea:
Create a web crawler that uses goroutines to fetch multiple URLs concurrently, with proper error handling and rate limiting. The crawler should use channels to coordinate between workers and collect results.