Exiting Multiple Goroutines Simultaneously
The ability to close channels (using Go’s builtin close()
function)
forms the basis of a useful pattern in Go:
using a single channel to exit multiple goroutines.
Let’s say we have launched a variable number of goroutines in the background as follows:
shutdown := make(chan struct{})
done := make(chan int)
for i := 0; i < n; i++ {
i := i
go func() {
select {
case <-shutdown:
done <- i
}
}()
}
Once started, each goroutine will wait for a signal
from a single shutdown
channel before exiting.
We would like to signal all n
goroutines to be shut down
at once in the most elegant way possible. To do so, we can
make use of the
fact that receiving on a closed channel will never block.
Simply by closing the shutdown
channel, we can
signal all goroutines to “unblock,” causing them to
immediately exit. A complete example is given below:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package main
import (
"fmt"
"time"
)
var (
shutdown = make(chan struct{})
done = make(chan int)
)
func main() {
const n = 5
// Start up the goroutines...
for i := 0; i < n; i++ {
i := i
go func() {
select {
case <-shutdown:
done <- i
}
}()
}
time.Sleep(2 * time.Second)
// Close the channel. All goroutines will immediately "unblock".
close(shutdown)
for i := 0; i < n; i++ {
fmt.Println("routine", <-done, "has exited!")
}
}
You can also view and run the above example on the Go Playground.
Let me know if you found this pattern helpful in the comments below, and don’t forget to +1 this post!
Recommended Readings:
- Documentation for the builtin
close
function in Go. - Closing a channel in the Go Programming Language Specification.
- Curious Channels by Dave Cheney.