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.WaitGroup
to 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!