1
+ package main
2
+
3
+ import (
4
+ "fmt"
5
+ )
6
+
7
+ func main () {
8
+ // read NOTE ONE below
9
+ c1 := incrementor ("1" )
10
+ c2 := incrementor ("2" )
11
+ // NOTE TWO
12
+ // the flow of code continues here in main
13
+ // incrementor is called
14
+ // launches goroutines
15
+ // returns channels which will eventually be closed
16
+ // by the code that is running in the goroutines
17
+ // launched by incrementor
18
+ // program flow in main continues on down vertically here
19
+
20
+ // NOTE THREE
21
+ // you're passing into "fanIn" two channels
22
+ // fanIn HAS TO pull values off of those channels
23
+ // otherwise: DEADLOCK
24
+ // fanIn will need to launch goroutines to pull those values
25
+ c := fanIn (c1 , c2 )
26
+
27
+ // NOTE SEVEN
28
+ // we are held up here
29
+ // pulling values off of c
30
+ // until c is closed
31
+ // and all values have been pulled from c
32
+ // at which point ...
33
+ for n := range c {
34
+ fmt .Println (n )
35
+ }
36
+
37
+ // NOTE EIGHT
38
+ // our program is done
39
+ // flow of code exits out of main
40
+ // program ends
41
+ }
42
+
43
+ func incrementor (s string ) <- chan string {
44
+ c := make (chan string )
45
+ go func () {
46
+ for i := 0 ; i < 20 ; i ++ {
47
+ // NOTE NINE
48
+ // use Sprint here, or Sprintln, not Sprintf
49
+ // this code is formatted for Sprintln
50
+ // Sprintf would need this
51
+ // c <- fmt.Sprintf("Process: %v, printing %v", s, i)
52
+ c <- fmt .Sprint ("Process: " + s + " printing:" , i )
53
+ }
54
+ // NOTE ONE
55
+ // incrementor
56
+ // every time it's called
57
+ // create a channel, put values on the channel
58
+ // ******** important ********
59
+ // have some other goroutine somewhere
60
+ // pulling values off the channel
61
+ // ***************************
62
+ // close the channel
63
+ // return that closed channel
64
+ // these "incrementor" goroutines are off and running
65
+ close (c )
66
+ }()
67
+ return c
68
+ }
69
+
70
+ // FAN IN
71
+ func fanIn (input1 , input2 <- chan string ) <- chan string {
72
+ c := make (chan string )
73
+ done := make (chan bool )
74
+
75
+ // NOTE FOUR
76
+ // these goroutines will pull values off the "incrementor" channels
77
+ // I'm defining the func to have a channel as a parameter and
78
+ // I'm passing the channels in as an argument
79
+ // as this is good practice to avoid different channels
80
+ // accessing the same data and creating a race condition
81
+ // not needed here, but good practice
82
+ // and good to know about
83
+
84
+ go func (x <- chan string ) {
85
+ for n := range x {
86
+ c <- n
87
+ }
88
+ done <- true
89
+ }(input1 )
90
+
91
+ go func (x <- chan string ) {
92
+ for n := range x {
93
+ c <- n
94
+ }
95
+ done <- true
96
+ }(input2 )
97
+
98
+ // NOTE FIVE
99
+ // this will signal when we're done writing values to c
100
+ go func () {
101
+ <- done
102
+ <- done
103
+ close (c )
104
+ }()
105
+
106
+ // NOTE SIX
107
+ // all of the above code
108
+ // just flows straight through
109
+ // goroutines are launched
110
+ // and even though they're not done processing
111
+ // program flow comes to here and this func returns
112
+ // the channel c
113
+ return c
114
+ }
0 commit comments