github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/blog/content/pipelines/sqdone3.go (about) 1 // +build OMIT 2 3 package main 4 5 import ( 6 "fmt" 7 "sync" 8 ) 9 10 // gen sends the values in nums on the returned channel, then closes it. 11 func gen(done <-chan struct{}, nums ...int) <-chan int { 12 out := make(chan int, len(nums)) 13 for _, n := range nums { 14 // We ignore done here because these sends cannot block. 15 out <- n 16 } 17 close(out) 18 return out 19 } 20 21 // sq receives values from in, squares them, and sends them on the returned 22 // channel, until in or done is closed. Then sq closes the returned channel. 23 func sq(done <-chan struct{}, in <-chan int) <-chan int { 24 out := make(chan int) 25 go func() { 26 defer close(out) // HL 27 for n := range in { 28 select { 29 case out <- n * n: 30 case <-done: 31 return // HL 32 } 33 } 34 }() 35 return out 36 } 37 38 // merge receives values from each input channel and sends them on the returned 39 // channel. merge closes the returned channel after all the input values have 40 // been sent or after done is closed. 41 func merge(done <-chan struct{}, cs ...<-chan int) <-chan int { 42 var wg sync.WaitGroup 43 out := make(chan int) 44 45 // Start an output goroutine for each input channel in cs. output 46 // copies values from c to out until c or done is closed, then calls 47 // wg.Done. 48 output := func(c <-chan int) { 49 defer wg.Done() // HL 50 for n := range c { 51 select { 52 case out <- n: 53 case <-done: 54 return // HL 55 } 56 } 57 } 58 // ... the rest is unchanged ... 59 60 wg.Add(len(cs)) 61 for _, c := range cs { 62 go output(c) 63 } 64 65 // Start a goroutine to close out once all the output goroutines are 66 // done. This must start after the wg.Add call. 67 go func() { 68 wg.Wait() 69 close(out) 70 }() 71 return out 72 } 73 74 func main() { 75 // Set up a done channel that's shared by the whole pipeline, 76 // and close that channel when this pipeline exits, as a signal 77 // for all the goroutines we started to exit. 78 done := make(chan struct{}) // HL 79 defer close(done) // HL 80 81 in := gen(done, 2, 3) 82 83 // Distribute the sq work across two goroutines that both read from in. 84 c1 := sq(done, in) 85 c2 := sq(done, in) 86 87 // Consume the first value from output. 88 out := merge(done, c1, c2) 89 fmt.Println(<-out) // 4 or 9 90 91 // done will be closed by the deferred call. // HL 92 }