Buffered vs. unbuffered channels

suggest change

By default channels are unbuffered.

Sending and receiving goroutines block unless sending goroutine has a value to send and receiving goroutine is ready to receive.

Insisting on synchronization for every receive/send operation might introduce unnecessary slowdowns.

Imagine a scenario where one worker produces values and another worker consumes it.

If it takes a second to produce a value and a second to consume it, it takes 2 * N seconds to produce and consume all values.

If producer can queue up multiple values in the channel, producer doesn’t have to wait for consumer to be ready for each value.

This is a job for buffered channels.

By allowing producer to proceed independently of the consumer we can speed up some scenarios.

func producer(ch chan int) {
	for i := 0; i < 5; i++ {
		if i%2 == 0 {
			time.Sleep(10 * time.Millisecond)
		} else {
			time.Sleep(1 * time.Millisecond)
		}
		ch <- i
	}
}

func consumer(ch chan int) {
	total := 0
	for i := 0; i < 5; i++ {
		if i%2 == 1 {
			time.Sleep(10 * time.Millisecond)
		} else {
			time.Sleep(1 * time.Millisecond)
		}
		total += <-ch
	}
}

func unbuffered() {
	timeStart := time.Now()
	ch := make(chan int)
	go producer(ch)
	consumer(ch)
	fmt.Printf("Unbuffered version took %s\n", time.Since(timeStart))
}

func buffered() {
	timeStart := time.Now()
	ch := make(chan int, 5)
	go producer(ch)
	consumer(ch)
	fmt.Printf("Buffered version took %s\n", time.Since(timeStart))
}

func main() {
	unbuffered()
	buffered()
}
Unbuffered version took 50.974968ms
Buffered version took 32.641641ms

Feedback about page:

Feedback:
Optional: your email if you want me to get back to you:



Table Of Contents