Channels and select
suggest changeA channel is a thread-safe queue of values of a given type.
A primary use for channels is to communicate between goroutines.
For that reason we talk about sending values to a channel (ch <- value
) and receiving values from a channel (value <- ch
).
Basic of channels:
func genInts(chInts chan int) {
chInts <- rand.Intn(1000)
}
func main() {
chInts := make(chan int)
for i := 0; i < 2; i++ {
go genInts(chInts)
}
n := <-chInts
fmt.Printf("n: %d\n", n)
select {
case n := <-chInts:
fmt.Printf("n: %d\n", n)
}
}
n: 81
n: 887
Zero value of a channel is nil
. Sending to nil
channel blocks forever so the first thing to do is to create a channel with make(chan <type>, <queue size>)
. Queue size is optional and defaults to unbuffered channel (you can think of it as size 0).
Send operator chan <- value
puts the value at the end of the queue.
If channel is full, <-
will block.
Send on a nil
channel blocks forever.
Retrieve statement value = <- chan
picks up the value from the front of the queue.
If channel is empty, retrieve will block.
Another way to retrieve a value form channel is to use select
statement.
Using select
allows to:
- wait on multiple channels
- do a non-blocking wait
- implement timeouts by waiting on a timer channel
Yet another is to use range.
Channels have a fixed capacity.
Channel created without explicit size (e.g. make(chan int)
) has size 0 and is called unbuffered channel. Send on unbuffered channel blocks until a corresponding receive completes.
Channel created with explicit size (e.g. make(chan int, 3)
) is called buffered channel with capacity of 3.
The first 3 sends will finish immediately, the 4th send will block until a value is received from the channel.
You can close a channel with close(chan)
.
Closing channel twice panics.
Sending to closed channel panics.
A receive from closed channels:
- returns buffered values
- return zero value immediately if there are no more buffered values
Closing a channel also ends range
loop over a channel.