1  package main
   2  
   3  import ( "fmt"; "os"; "flag"; "strconv"; "rand" )
   4  
   5  /*
   6   * Make a channel and a goroutine. When the channel
   7   * is written to, the goroutine will print out the
   8   * incoming integer.
   9   *
  10   * When the channel is closed, this closes the "done"
  11   * channel and exits, signalling completion.
  12   */
  13  func printer(done chan int) chan int {
  14    ch := make(chan int)
  15    
  16    go func() {
  17      for {
  18        i := <- ch
  19  
  20        if i == 0 && closed(ch) {
  21          close(done)
  22          break
  23        }
  24  
  25        fmt.Printf("%d\n", i)
  26      }
  27    }()
  28    
  29    return ch
  30  }
  31  
  32  /*
  33   * Make a channel and a goroutine. When the channel
  34   * is written to, the goroutine will add N to the
  35   * incoming integer and pass it to the next channel.
  36   *
  37   * If the channel is closed, this closes the next
  38   * channel and exits.
  39   */
  40  func adder(next chan int, n int) chan int {
  41    ch := make(chan int)
  42    
  43    go func() {
  44      for {
  45        i := <- ch
  46        
  47        if i == 0 && closed(ch) {
  48          close(next)
  49          break
  50        }
  51        
  52        next <- i + n
  53      }
  54    }()
  55    
  56    return ch
  57  }
  58  
  59  /*
  60   * Process the command-line and spawn the pipeline
  61   */
  62  func main() {
  63    if flag.NArg() != 1 {
  64      os.Stderr.WriteString("Usage: counter <N>\n")
  65      os.Exit(1)
  66    }
  67  
  68    n, err := strconv.Atoi(flag.Arg(0))
  69    
  70    if err != nil {
  71      fmt.Fprintf(os.Stderr, "The argument must be a number (%v)\n", err)
  72      os.Exit(1)
  73    }
  74    
  75    // Create N channels, each with work to do. The last channel
  76    // will do the printing.
  77    
  78    done := make(chan int)
  79    ch := printer(done)
  80    
  81    for i := n; i > 0; i-- {
  82      ch = adder(ch, i)
  83    }
  84    
  85    // Generate 10,000 random numbers from 1 to 20 and send them through
  86    // the pipeline.
  87  
  88    for i := 0; i < 10000; i++ {
  89      r := rand.Intn(20) + 1
  90      ch <- r
  91    }
  92    
  93    // Close the pipeline and wait for it to exit
  94    close(ch)
  95    <- done
  96  }