github.com/qiuhoude/go-web@v0.0.0-20220223060959-ab545e78f20d/prepare/18channeluse/or_channel_reflect/main.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"time"
     7  )
     8  
     9  /*
    10  Go的反射库针对select语句有专门的数据(reflect.SelectCase)和函数(reflect.Select)处理。
    11  所以我们可以利用反射“随机”地从一组可选的channel中接收数据,并关闭输出channel。
    12  */
    13  func or(chans ...<-chan interface{}) <-chan interface{} {
    14  	switch len(chans) {
    15  	case 0:
    16  		return nil
    17  	case 1:
    18  		return chans[0]
    19  	}
    20  	orDone := make(chan interface{})
    21  	go func() {
    22  		defer close(orDone)
    23  		var cases []reflect.SelectCase
    24  		for _, c := range chans {
    25  			cases = append(cases, reflect.SelectCase{
    26  				Dir:  reflect.SelectRecv,
    27  				Chan: reflect.ValueOf(c),
    28  			})
    29  		}
    30  		reflect.Select(cases)
    31  	}()
    32  	return orDone
    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(3*time.Second),
    49  		sig(20*time.Second),
    50  		sig(30*time.Second),
    51  		sig(40*time.Second),
    52  		sig(01*time.Minute),
    53  	)
    54  	fmt.Printf("done after %v", time.Since(start))
    55  }