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  }