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 closefunction in Go.
- Closing a channel in the Go Programming Language Specification.
- Curious Channels by Dave Cheney.