go · level 3 · unit 5 · lesson 3
- meet it
- guess first
- your turn
- fix it
- nailed it
Tap a green word if you get lost.
meet it
Fan out the work, then fan the results back in to one channel.
spreads work across goroutines: one per site to check, or several readers sharing one input channel. Each value is handled by exactly one of them. gathers their results into a single channel, so the code that reads them has one place to look.
But who closes a channel with many senders? Not a sender: it cannot know the others are finished. A waits on a WaitGroup until every sender has called Done, then closes the channel, so the reader's range ends.
The general tool is often called merge: it fans in any number of channels this way. Fan-in mixes the order, so sort before printing.
package main
import (
"fmt"
"sort"
"sync"
)
func check(sites []string) <-chan string {
out := make(chan string)
var wg sync.WaitGroup
for _, s := range sites {
wg.Add(1)
go func(s string) { defer wg.Done(); out <- s + " is up" }(s)
}
go func() { wg.Wait(); close(out) }()
return out
}
func main() {
var report []string
for line := range check([]string{"eu", "us", "asia"}) {
report = append(report, line)
}
sort.Strings(report)
fmt.Printf("%q\n", report)
} check returns straight away; the closer goroutine finishes the job in the background.
guess first
Three readers share two files. How many results?
Guess before you run it. Wrong guesses are how you learn, and nothing is marked.
package main
import (
"fmt"
"sync"
)
func main() {
in := make(chan string, 2)
in <- "a.txt"
in <- "b.txt"
close(in)
out := make(chan string, 6)
var wg sync.WaitGroup
for c := 0; c < 3; c++ {
wg.Add(1)
go func() {
defer wg.Done()
for f := range in {
out <- f
}
}()
}
wg.Wait()
fmt.Println(len(out))
}
your turn
Your turn. Write the closer goroutine.
Add a third site to check. Then finish the closer goroutine: wait for every sender, then close out.
output
press run to see what happens
fix it
The site check never returns. Can you fix it?
output
press run to see what happens
- It is a deadlock. The senders wait for someone to receive, and
checkwaits for the senders. Who is left to receive? maincannot receive anything untilcheckreturns, andcheckis stuck inwg.Wait().- Move the waiting into a closer goroutine:
go func() { wg.Wait(); close(out) }().
nailed it
many senders, one channel, one closer. :D
- Fan-out shares work; each value goes to one goroutine.
- Fan-in gathers results into a single channel.
- A closer goroutine waits for every sender, then closes.
new words in your collection
- fan-out
- fan-in
- closer goroutine
This lesson isn’t saved. A free account remembers every lesson you finish.