Channels
ch := make(chan type)
ch <- value // send
value := <-ch // receive
close(ch)
Creating and Using a Channel
make(chan Type) creates a channel that carries values of that type between goroutines. Values are sent with ch <- value and received with <-ch, and by default these operations block until the other side is ready.
Example: Creating and Using a Channel
// Every Go file belongs to a package; main builds an executable
package main
// Import the fmt package
import "fmt"
// main is where the program starts running
func main() {
// Short declaration: create ch and infer the type
ch := make(chan string)
// Start this call in a new goroutine (runs concurrently)
go func() {
ch <- "message from goroutine"
}()
// Short declaration: create msg and infer the type
msg := <-ch
// Print the values followed by a newline
fmt.Println(msg)
}
Login to try C/C++/Java/PHP code in the editor
Channels as Synchronization
Because a receive blocks until a value is sent, channels naturally synchronize goroutines -- the receiving side waits precisely until the sending goroutine has reached that point in its work.
Example: Channels as Synchronization
// Every Go file belongs to a package; main builds an executable
package main
// Import the fmt package
import "fmt"
// Define the function worker
func worker(done chan bool) {
// Print the values followed by a newline
fmt.Println("working...")
done <- true
}
// main is where the program starts running
func main() {
// Short declaration: create done and infer the type
done := make(chan bool)
// Start this call in a new goroutine (runs concurrently)
go worker(done)
<-done
// Print the values followed by a newline
fmt.Println("worker finished, main continues")
}
Login to try C/C++/Java/PHP code in the editor
Closing a Channel
Closing a channel with close(ch) signals that no more values will be sent. Receivers can detect this with the comma-ok form, and range over a channel automatically stops when it's closed.
Example: Closing a Channel
// Every Go file belongs to a package; main builds an executable
package main
// Import the fmt package
import "fmt"
// main is where the program starts running
func main() {
// Short declaration: create ch and infer the type
ch := make(chan int)
// Start this call in a new goroutine (runs concurrently)
go func() {
// Loop: repeat while the condition holds
for i := 1; i <= 3; i++ {
ch <- i
}
close(ch)
}()
for v := range ch {
// Print the values followed by a newline
fmt.Println(v)
}
}
Login to try C/C++/Java/PHP code in the editor
- Sending on a channel that nobody is ever going to receive from, causing the sending goroutine to block forever (deadlock).
- Forgetting an unbuffered channel send blocks until a receiver is ready, and vice versa -- it's a rendezvous, not a mailbox.
- Reading from a closed channel expecting it to block or error, when it instead immediately returns the type's zero value.
- A channel, created with make(chan Type), lets goroutines send and receive values safely.
- Sending (ch <- v) and receiving (<-ch) on an unbuffered channel block until both sides are ready.
- Channels are the idiomatic way to synchronize and communicate between goroutines, per Go's 'share memory by communicating' philosophy.
- Reading from a closed channel returns the zero value immediately instead of blocking.
Chapter Quiz — Complete all 8 topics to unlock
0/8 topics done
Complete these topics first: