github.com/qiuhoude/go-web@v0.0.0-20220223060959-ab545e78f20d/prepare/18channeluse/or_channel_go/main.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "sync" 6 "time" 7 ) 8 9 /* 10 提供相同服务的n个节点发送请求,只要任意一个服务节点返回结果, 11 我们就可以执行下面的业务逻辑,其它n-1的节点的请求可以被取消或者忽略 12 */ 13 14 //or函数可以处理n个channel,它为每个channel启动一个goroutine, 15 // 只要任意一个goroutine从channel读取到数据,输出的channel就被关闭掉了。 16 func or(chans ...<-chan interface{}) <-chan interface{} { 17 out := make(chan interface{}) 18 go func() { 19 var once sync.Once 20 for _, c := range chans { 21 go func(ch <-chan interface{}) { 22 select { 23 case <-ch: 24 once.Do(func() { // 为了避免并发关闭输出channel的问题,关闭操作只执行一次 25 close(out) 26 }) 27 case <-out: 28 } 29 }(c) 30 } 31 }() 32 return out 33 } 34 35 func main() { 36 sig := func(after time.Duration) <-chan interface{} { 37 c := make(chan interface{}) 38 go func() { 39 defer close(c) 40 time.Sleep(after) 41 }() 42 return c 43 } 44 45 start := time.Now() 46 <-or( 47 sig(10*time.Second), 48 sig(5*time.Second), 49 sig(10*time.Second), 50 sig(10*time.Second), 51 sig(10*time.Second), 52 sig(01*time.Minute), 53 ) 54 fmt.Printf("done after %v", time.Since(start)) 55 }