用channel优雅地收集多协程运行结果

108 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第11天,点击查看活动详情

🎐 放在前面说的话

大家好,我是沥沥樱 👧🏻

本科在读,此为日常捣鼓.

如有不对,请多指教,也欢迎大家来跟我讨论鸭 👏👏👏

还有还有还有很重要的,麻烦大可爱们动动小手,给沥沥樱点颗心心♥,沥沥樱需要鼓励嗷呜~

今天我们要用channel优雅地收集多协程运行结果

Let’s get it!

channel的使用场景

channel主要用在数据流动的地方

  1. 消息传递、消息过滤
  2. 信号广播
  3. 事件订阅与广播
  4. 请求、响应转发
  5. 任务分发
  6. 结果汇总
  7. 并发控制
  8. 同步与异步
  9. ...

下面我们来讲一下利用channel对多协程进行结果汇总

结果汇总

Go协程通常使用channel(通道)通讯从而协调/同步它们的工作。合理利用Go协程和channel能帮助我们大大提升程序的性能。比如,有些时候我们需要同时执行多个协程,然后再根据其结果再进行处理,这时候收集多个协程的值就非常关键。

基础代码

单个协程执行完毕,直接打印

func main() {
	var wg sync.WaitGroup
	for i := 0; i < 5; i++ { // 开启5个协程
		wg.Add(1)
		go func(index int) {
			fmt.Println(index)
		}(i)
	}
	wg.Done()
	time.Sleep(time.Second)
}

因为协程执行是无序的,所以打印出来的并不一定时顺序的
打印: 4 1 0 3 2

channel汇总

在上面的代码基础上,使用channel对协程结果进行汇总并输出

func main() {
	var wg sync.WaitGroup
	ch := make(chan int)
	for i := 0; i < 5; i++ { // 开启5个协程
		wg.Add(1)
		go func(index int) {
			defer wg.Done()
			ch <- index // 将写成数据写入channel
		}(i)
	}
        // 等待所有goroutine执行完之后再关闭通道 defer方式关闭
	go func() {
		defer close(ch)
		wg.Wait()
	}()
	time.Sleep(time.Second)
	for msg := range ch {
		fmt.Println(msg) // 遍历channel
	}
}

打印: 0 1 4 2 3

解决在取数据时不关注 channel 里面的协程是否处理完了的原理,再开一个协程跑 wg.Wait,因为它能确保被挂在 wg 里面的所有协程都执行完毕了才会被执行,有点想监工的感觉。

🎉 放在后面说的话

以上简单举了一个channel收集多协程运行结果的栗子