github.com/kaydxh/golang@v0.0.131/tutorial/programming_paradigm/pipeline_test.go (about) 1 package tutorial 2 3 import ( 4 "fmt" 5 "math" 6 "sync" 7 "testing" 8 ) 9 10 //通过channel 与 gorutinue 实现Fan in/Out, 1对多/多对1 11 //Multiple functions can read from the same channel until that channel 12 //is closed; this is called fan-out 13 //https://go.dev/blog/pipelines 14 15 // echo 将整数数组放入到channel中,并返回 channel 16 func echo(nums []int) <-chan int { 17 out := make(chan int) 18 go func() { 19 for _, n := range nums { 20 out <- n 21 } 22 close(out) 23 }() 24 return out 25 } 26 27 // sum内部使用一个协程处理从in读取的数据, 如果多次调用sum,就可以实现将 28 // 同一个chan 中的数据分成多个协程进行并发处理(读取数据这块是串行,单处理是并发) 29 func sum(in <-chan int) <-chan int { 30 out := make(chan int) 31 go func() { 32 var sum = 0 33 for n := range in { 34 sum += n 35 } 36 out <- sum 37 //close 作用的是让外部读取out chanel停止调,不会会永远阻塞 38 close(out) 39 }() 40 return out 41 } 42 43 func is_prime(value int) bool { 44 for i := 2; i <= int(math.Floor(float64(value)/2)); i++ { 45 if value%i == 0 { 46 return false 47 } 48 } 49 return value > 1 50 } 51 52 func prime(in <-chan int) <-chan int { 53 out := make(chan int) 54 go func() { 55 for n := range in { 56 if is_prime(n) { 57 out <- n 58 } 59 } 60 close(out) 61 }() 62 return out 63 } 64 65 // 66 func merge(cs []<-chan int) <-chan int { 67 var wg sync.WaitGroup 68 out := make(chan int) 69 70 wg.Add(len(cs)) 71 for _, c := range cs { 72 go func(c <-chan int) { 73 for n := range c { 74 out <- n 75 } 76 wg.Done() 77 }(c) 78 } 79 //协程的目的是让外部读取out的函数先工作起来,等到所有协程都完成工作 80 //后,close调,中断外部读取操作 81 go func() { 82 wg.Wait() 83 // 关闭读取前,等待所有的协程完成任务 84 close(out) 85 }() 86 return out 87 } 88 89 //生成指定范围的数组 90 func makeRange(min, max int) []int { 91 a := make([]int, max-min+1) 92 for i := range a { 93 a[i] = min + i 94 } 95 return a 96 } 97 98 func TestPipleline(t *testing.T) { 99 nums := makeRange(1, 10000) 100 // echo 将整数数组放入到channel中,并返回 channel 101 in := echo(nums) 102 103 const nProcess = 5 104 var chans [nProcess]<-chan int 105 for i := range chans { 106 107 // 将chan in中的数据分成5个协程处理, 结果输出到5个chan中 108 chans[i] = sum(prime(in)) 109 } 110 111 /* 112 n := <-sum(merge(chans[:])) 113 fmt.Println(n) 114 */ 115 //如果有多个结果的话,使用range读取结果 116 for n := range sum(merge(chans[:])) { 117 fmt.Println(n) 118 } 119 120 }