# Unbuffered vs Buffered Channels — Go Concurrency Patterns

Source: https://www.skillbyai.com/en/go-concurrency/gc-buffering

> When sends and receives block.

## Blocking semantics

`make(chan T)` creates an **unbuffered** channel: a send blocks until a receiver takes the value, and a receive blocks until a sender provides one, so the two goroutines **synchronise** at the hand-off. `make(chan T, n)` creates a **buffered** channel with capacity `n`: a send blocks only when the buffer is full, and a receive blocks only when it is empty. `len(ch)` and `cap(ch)` report the number of queued items and the capacity, but `len` is stale as soon as you read it, so do not use it for coordination. Buffers smooth out bursts and decouple producer and consumer speeds; they do not fix a design where the consumer is permanently slower. A send with no possible receiver blocks forever; if every goroutine is blocked like that, the runtime aborts with `fatal error: all goroutines are asleep - deadlock!`

## Typed pipes between goroutines

Channels move values between goroutines and synchronise them; their blocking rules are the heart of Go concurrency.

![Three ideas: buffering and blocking, closing and ranging, and channel direction in APIs.](assets/figures/go-concurrency/section-2-map.svg) — Figure 2.1: a sender, a channel and a receiver.

## Unbuffered hand-off vs buffered queue

The unbuffered send waits for the receiver; the buffered sends do not.

```go
package main

import "fmt"

func main() {
	// Unbuffered: the send completes only when main receives.
	done := make(chan string)
	go func() { done <- "work finished" }()
	fmt.Println(<-done)

	// Buffered with capacity 2: two sends succeed without a receiver.
	queue := make(chan int, 2)
	queue <- 1
	queue <- 2
	fmt.Println(len(queue), cap(queue)) // 2 2
	// queue <- 3 would block here: buffer full and nobody receiving.
	fmt.Println(<-queue, <-queue)       // FIFO order: 1 2
}
```

## Choose buffer sizes deliberately

Default to unbuffered or a buffer of 1. A larger buffer should have a reason you can state, such as "at most N in-flight jobs"; a big buffer chosen to make a deadlock disappear usually just postpones it.

**Quiz:** When does a send on a buffered channel with capacity 3 block?

- [ ] Always, until a receiver is ready
- [x] When the buffer already holds 3 values
- [ ] Never, buffered sends are non-blocking
- [ ] Only after the channel is closed

*Answer:* When the buffer already holds 3 values. A buffered send blocks only when the buffer is full.
