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  }