github.com/qiuhoude/go-web@v0.0.0-20220223060959-ab545e78f20d/prepare/18channeluse/fanout/main.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "reflect" 6 "time" 7 ) 8 9 /* 10 扇出模式(FanOut)是将一个输入channel扇出为多个channel。 11 12 扇出行为至少可以分为两种: 13 14 1. 从输入channel中读取一个数据,发送给每个输入channel,这种模式称之为Tee模式; 个人理解:有点类似于redis中的订阅发布 15 2. 从输入channel中读取一个数据,在输出channel中选择一个channel发送 16 */ 17 18 //1. 19 // 一个输入 ,多个输出 20 func fanOut1(ch <-chan interface{}, out []chan interface{}, async bool) { 21 go func() { 22 defer func() { 23 for i := 0; i < len(out); i++ { 24 close(out[i]) 25 } 26 }() 27 for v := range ch { 28 v := v // 重新声明,避免闭包应用问题 29 for i := 0; i < len(out); i++ { 30 i := i 31 if async { 32 go func() { 33 out[i] <- v 34 }() 35 } else { 36 out[i] <- v 37 } 38 } 39 } 40 }() 41 } 42 43 // 递归方式 44 func fanOut1Reflect(ch <-chan interface{}, out []chan interface{}) { 45 go func() { 46 defer func() { 47 for i := 0; i < len(out); i++ { 48 close(out[i]) 49 } 50 }() 51 cases := make([]reflect.SelectCase, len(out)) 52 for i := range cases { 53 cases[i].Dir = reflect.SelectSend // 发送选择 54 } 55 56 for v := range ch { 57 v := v 58 for i := range cases { 59 cases[i].Chan = reflect.ValueOf(out[i]) 60 cases[i].Send = reflect.ValueOf(v) 61 } 62 // 选择 63 for _ = range cases { 64 i, _, _ := reflect.Select(cases) 65 cases[i].Chan = reflect.ValueOf(nil) 66 } 67 } 68 69 }() 70 } 71 72 // 2. 73 // 一个输入, 选其中一个输出 分布模式 74 func fanOut2(ch <-chan interface{}, out []chan interface{}) { 75 go func() { 76 defer func() { 77 for i := 0; i < len(out); i++ { 78 close(out[i]) 79 } 80 }() 81 82 // roundrobin 83 var i = 0 84 var n = len(out) 85 for v := range ch { 86 v := v 87 out[i] <- v 88 i = (i + 1) % n 89 } 90 }() 91 } 92 93 func fanOut2Reflect(ch <-chan interface{}, out []chan interface{}) { 94 go func() { 95 defer func() { 96 for i := 0; i < len(out); i++ { 97 close(out[i]) 98 } 99 }() 100 101 cases := make([]reflect.SelectCase, len(out)) 102 for i := range cases { 103 cases[i].Dir = reflect.SelectSend 104 cases[i].Chan = reflect.ValueOf(out[i]) 105 106 } 107 108 for v := range ch { 109 v := v 110 for i := range cases { 111 cases[i].Send = reflect.ValueOf(v) 112 } 113 _, _, _ = reflect.Select(cases) 114 } 115 }() 116 } 117 118 func asStream(done <-chan struct{}) <-chan interface{} { 119 s := make(chan interface{}) 120 values := []int{1, 2, 3, 4, 5} 121 go func() { 122 defer close(s) 123 124 for _, v := range values { 125 select { 126 case <-done: 127 return 128 case s <- v: 129 } 130 } 131 132 }() 133 return s 134 } 135 136 func runFanout1() { 137 source := asStream(nil) 138 channels := make([]chan interface{}, 5) 139 140 fmt.Println("fanOut1") 141 for i := 0; i < 5; i++ { 142 channels[i] = make(chan interface{}) 143 } 144 fanOut1(source, channels, false) 145 for i := 0; i < 5; i++ { 146 for j := 0; j < 5; j++ { 147 fmt.Printf("channel#%d: %v\n", j, <-channels[j]) 148 } 149 } 150 151 fmt.Println("\nfanOut1 By Reflect") 152 source = asStream(nil) 153 for i := 0; i < 5; i++ { 154 channels[i] = make(chan interface{}) 155 } 156 fanOut1Reflect(source, channels) 157 for i := 0; i < 5; i++ { 158 for j := 0; j < 5; j++ { 159 fmt.Printf("channel#%d: %v\n", j, <-channels[j]) 160 } 161 } 162 } 163 func runFanout2() { 164 done := make(chan struct{}) 165 source := asStream(done) 166 channels := make([]chan interface{}, 5) 167 168 fmt.Println("fanOut") 169 for i := 0; i < 5; i++ { 170 channels[i] = make(chan interface{}) 171 } 172 fanOut2(source, channels) 173 for i := 0; i < 5; i++ { 174 i := i 175 go func() { 176 for j := 0; j < 5; j++ { 177 v, ok := <-channels[i] 178 if ok { 179 fmt.Printf("channel#%d: %v\n", i, v) 180 } 181 182 } 183 }() 184 } 185 time.Sleep(time.Second) 186 close(done) 187 188 fmt.Println("fanOut By Reflect") 189 done = make(chan struct{}) 190 source = asStream(done) 191 for i := 0; i < 5; i++ { 192 channels[i] = make(chan interface{}) 193 } 194 fanOut2Reflect(source, channels) 195 for i := 0; i < 5; i++ { 196 i := i 197 go func() { 198 for j := 0; j < 5; j++ { 199 v, ok := <-channels[i] 200 if ok { 201 fmt.Printf("channel#%d: %v\n", i, v) 202 } 203 } 204 }() 205 } 206 time.Sleep(time.Second) 207 close(done) 208 } 209 210 func main() { 211 212 //runFanout1() 213 runFanout2() 214 }