12 - Now you're thinking with channels
Covered in this module:
- channels
channels
Channels are mono-directional pipes that goroutines can use to communicate.
To create a channel use make(chan <type>)
where type is the type of the values that will be passed in the channel.
To send a value to a channel you use the syntax channel <- value
.
To receive a value from a channel, use <-channel
and capture the retrieved value into a variable like variable := <-channel
:
func main() {
randInts := make(chan int)
go roll1d6(randInts)
roll := <-randInts // this pulls new rolls from the channel
fmt.Println("You rolled a", roll)
}
func roll1d6(c chan int) {
c <- rand.Intn(6) + 1 // this passes new rolls into the channel
}
If you are just using the channel as a ping mechanism (i.e. you don't care about the value in the channel), you can receive with simply <-channel
without capturing the retrieved value.
func main() {
ping := make(chan bool)
startTime := time.Now()
go waitForPing(ping)
<-ping
fmt.Println("Program took", time.Since(startTime))
}
func waitForPing(c chan bool) {
time.Sleep(time.Second * 1)
c <- true
}
prints
Program took 1.00006811s
Send and receive on channels are both blocking. Go will block the enclosing goroutine until both sides of the channel are ready.
You can specify whether a channel is to be used for sending or receiving as part of the function parameter list:
func main() {
randInts := make(chan int)
done := make(chan bool)
go roll1d6(randInts)
go printRoll(randInts, done)
<-done
}
func roll1d6(c chan<- int) {
c <- rand.Intn(6) + 1
}
func printRoll(c <-chan int, done chan<- bool) {
fmt.Println("You rolled a", <-c)
done <- true
}
A channel can have any number of senders and receivers. A value going into a channel is guaranteed to be received by only one receiver.
Hands on!
- In the repo, open the file
./intermediate/12channels.go
- Complete the TODOs
- Run
make 12
from project root (alternatively, typego run ./12channels.go
) - Example implementation available on
solutions
branch