golang中channel的应用场景

  1. channel+goroutine是go并发的大杀器
  2. channel可以用来停止信号(发送信号停止子goroutine的执行)
  3. 超时控制(websocket中长时间不活跃的用户可以直接断开链接)
  4. 定时任务的执行
  5. 解耦生产方和消费方
  6. 控制最大并发数量

案例见下面:

* channel和goroutine的结合是go并发编程的大杀器
* 而channel和select、cancel、timer的结合能实现各种各样的功能
* 1. 停止信号:关闭channel或向channel发送一个元素,使接收方通过channel获得信息后做相应的操作
* 2. 任务定时:
    (1)超时控制
func main() {
    c := make(chan int)
    out := make(chan bool)
    go func() {
        go func() {
            time.Sleep(time.Second)
            c <- 2
        }()
        select {
        case <-time.After(time.Second * 1):
            fmt.Println("超时了")
        case v := <-c:
            fmt.Println("c中读取出的数据:", v)
        }
        out <- true
    }()
    <-out
}
    (2)定期执行某个任务
func main() {
	timer := time.NewTicker(time.Second)
	for {
		select {
		case <-timer.C:
			fmt.Println("执行了")  // 每隔1秒执行一次
		}
	}
}
3. 解耦生产方和消费方
服务启动时,启动n个worker,作为工作协程池,这些协程工作在一个for无限循环里, 从某个channel消费工作任务并执行
案例:
func main() {
	tasksChan := make(chan int, 100)  // 任务队列
	go workerTask(tasksChan)  // 开启处理任务的协程池
	// 发起任务
	for i := 0; i < 10; i++ {
		tasksChan <- i
	}
	select {
	case <-time.After(time.Second * 3):
	}
}
func workerTask(tasksChan chan int) {
	// 开启5个协程去处理任务队列中的数据
	GOS := 5
	for i := 0; i < GOS; i++ {
		// 局部变量在堆栈上存储,也是变量逃逸的一种场景(解决方法:使用闭包)
		go func(i int) {
			for {
				value := <-tasksChan
				fmt.Printf("finish task: %d by worker %d\n", value, i)
				time.Sleep(time.Second)
			}
		}(i)
	}
}

输出结果:

	finish task: 1 by worker 4
	finish task: 2 by worker 1
	finish task: 3 by worker 2
	finish task: 4 by worker 3
	finish task: 0 by worker 0
	finish task: 5 by worker 0
	finish task: 6 by worker 1
	finish task: 7 by worker 3
	finish task: 8 by worker 2
	finish task: 9 by worker 4
4. 控制并发数
有时需要定时执行几百个任务,例如每天定时按城市来执行一些离线计算的任务。但是并发数又不能太高,
因为任务执行过程依赖第三方的一些资源,对请求的速率有限制。这时就可以通过 channel 来控制并发数。
案例:
var limit = make(chan int, 3)

func main() {
	// 通过channel控制最大并发数量
	tasks := [...]int{11, 22, 33, 44, 55, 66, 77, 88, 99, 100}
	for i, v := range tasks {
		// 为每一个任务开启一个goroutine
		go func(i, v int) {
			// 通过channel控制goroutine最大并发数量
			limit <- -1
			fmt.Println(i, v)
			time.Sleep(time.Second)
			<-limit
		}(i, v)
	}
	time.Sleep(time.Second * 4)
}

posted @ 2022-02-18 11:11  专职  阅读(790)  评论(0编辑  收藏  举报