Concurrency¶
Go's goroutines and channels are core language features, compared to Python's threading and asyncio.
threading.Thread¶
func worker(name string) {
fmt.Printf("Hello from %s\n", name)
}
go worker("goroutine-1")
time.Sleep(time.Second) // simple wait (not production-ready)
When main exits, all goroutines are killed
When the main function returns, all goroutines are terminated immediately — they
won't finish. Use sync.WaitGroup or channels to wait properly.
queue.Queue¶
Channels are typed pipes for communication between goroutines.
ch := make(chan int)
// Producer
go func() {
for i := range 3 {
ch <- i
}
close(ch)
}()
// Consumer
for item := range ch {
fmt.Printf("Got: %d\n", item)
}
Unbuffered channels block
make(chan int) creates an unbuffered channel — the sender blocks until a receiver
is ready. Use make(chan int, 10) for a buffered channel that can queue values.
threading.Lock¶
asyncio¶
ThreadPoolExecutor¶
select (Go-specific)¶
select listens on multiple channels simultaneously, executing whichever case is ready first.
ch1 := make(chan string)
ch2 := make(chan string)
go func() { time.Sleep(1 * time.Second); ch1 <- "one" }()
go func() { time.Sleep(2 * time.Second); ch2 <- "two" }()
select {
case msg := <-ch1:
fmt.Println("Received from ch1:", msg)
case msg := <-ch2:
fmt.Println("Received from ch2:", msg)
case <-time.After(3 * time.Second):
fmt.Println("Timeout")
}
Buffered vs Unbuffered Channel (Go-specific)¶
unbuf := make(chan int) // unbuffered: send blocks until received
buf := make(chan int, 5) // buffered: can queue up to 5 values
// send does not block until the buffer is full
buf <- 1
buf <- 2
fmt.Println(<-buf) // 1
Avoid goroutine leaks
A goroutine waiting on a channel that never receives data will never terminate (leak).
Use context.WithCancel or context.WithTimeout to make goroutines cancellable: