Example 1
In the below code, <-messages will block until it gets something on the channel.
This prevents main() from exiting until one item is received on the channel.
package main
import (
"fmt"
"time"
)
func waitThenSend(msg chan string) {
time.Sleep(2 * time.Second)
msg <- "badwolf"
}
func main() {
messages := make(chan string) // make unbuffered channel
go func() {
waitThenSend(messages) // make goroutine, pass in channel
}()
<-messages // blocks until channel receives a value
fmt.Println("done")
}
Example 2
The below example demonstrates using a sync.WaitGroupto keep the program running until all of the goroutines have exited. Data is sent to the function via the unbuffered channel named numbers.
It is important to realize that fmt.Println("after:", i) does not get executed until fmt.Println("printing:", <-num) receives data because of the blocking nature of the unbuffered channel.
If we change numbers := make(chan int) to numbers := make(chan int, 10) to make it a buffered channel, it will not block our program because we only put 10 items in the channel. If we use 5 instead of 10, it will block after the channel receives 5 objects.
package main
import (
"fmt"
"sync"
"time"
)
func print(num chan int, wg *sync.WaitGroup) {
for {
time.Sleep(1 * time.Second)
fmt.Println("printing:", <-num)
wg.Done() // decrement waitgroup
}
}
func main() {
numbers := make(chan int) // make unbuffered channel
var wg sync.WaitGroup
go print(numbers, &wg)
for i := 0; i < 10; i++ {
i := i
wg.Add(1) // increment waitgroup
go func() {
fmt.Println("before:", i)
numbers <- i // blocks if nothing is listening to the *unbuffered* channel!
fmt.Println("after:", i)
}()
}
wg.Wait() // blocks until waitgroup is zero again
fmt.Println("done")
}
Neat!