github.com/songzhibin97/go-baseutils@v0.0.2-0.20240302024150-487d8ce9c082/app/bconcurrent/fan_in.go (about)

     1  package bconcurrent
     2  
     3  import "reflect"
     4  
     5  // FanInRec 扇入模式
     6  func FanInRec[T any](channels ...<-chan T) <-chan T {
     7  	out := make(chan T, 1)
     8  	go func() {
     9  		defer close(out)
    10  		var cases []reflect.SelectCase
    11  		for _, channel := range channels {
    12  			cases = append(cases, reflect.SelectCase{
    13  				Dir:  reflect.SelectRecv,
    14  				Chan: reflect.ValueOf(channel),
    15  			})
    16  		}
    17  		for len(cases) > 0 {
    18  			i, v, ok := reflect.Select(cases)
    19  			if !ok {
    20  				// 监控的channel已经关闭
    21  				cases = append(cases[:i], cases[i+1:]...)
    22  				continue
    23  			}
    24  			out <- v.Interface().(T)
    25  		}
    26  	}()
    27  	return out
    28  }
    29  
    30  // MergeChannel 合并两个channel
    31  func MergeChannel[T any](a, b <-chan T) <-chan T {
    32  	c := make(chan T)
    33  	go func() {
    34  		defer close(c)
    35  		for a != nil || b != nil {
    36  			select {
    37  			case v, ok := <-a:
    38  				if !ok {
    39  					a = nil
    40  					continue
    41  				}
    42  				c <- v
    43  			case v, ok := <-b:
    44  				if !ok {
    45  					b = nil
    46  					continue
    47  				}
    48  				c <- v
    49  			}
    50  		}
    51  	}()
    52  	return c
    53  }