写点什么

Golang 的通道复用上手(三)

作者:liuzhen007
  • 2021 年 12 月 29 日
  • 本文字数:2317 字

    阅读完需:约 8 分钟

Golang的通道复用上手(三)

目录

  • 前言

  • 正文

  • 结尾

前言

我们知道 Golang 中的通道都是一端写入,一端读取的。基本上都是一个通道处理自己的逻辑,和别的通道不相关。那么,Golang 中的通道能不能进行统一管理呢?今天我们就来看一看。

正文

既然我们已经打算实现多个通道的统一管理,换句话说就是多路复用,我们需要一个方向。先来看看目前的通道的状态,每个通道都有自己的处理协程。

我们看段代码:

package main
import ( "fmt")
func main() { // 定义一个通道ch1 ch1 := make(chan int)
// 开启子协程goroutine写入数据 go func() { for i := 0; i < 11; i++ { ch1 <- i fmt.Println("子协程ch1写入数据:", i) } close(ch1) //关闭通道 }() // 定义一个通道ch2 ch2 := make(chan int)
// 开启子协程goroutine写入数据 go func() { for i := 0; i < 11; i++ { ch2 <- i fmt.Println("子协程ch2写入数据:", i) } close(ch2) //关闭通道 }()
// 主协程读取ch1数据 for { v, ok := <-ch1 if !ok { fmt.Println("读取结束", ok) break } fmt.Println("主协程读取到ch1数据为:", v) }
// 主协程读取ch2数据 for { v, ok := <-ch2 if !ok { fmt.Println("读取结束", ok) break } fmt.Println("主协程读取到ch2数据为:", v) }
fmt.Println("主协程结束")}
复制代码

执行结果如下:

子协程ch1写入数据: 0主协程读取到ch1数据为: 0主协程读取到ch1数据为: 1子协程ch1写入数据: 1子协程ch1写入数据: 2主协程读取到ch1数据为: 2主协程读取到ch1数据为: 3子协程ch1写入数据: 3子协程ch1写入数据: 4主协程读取到ch1数据为: 4主协程读取到ch1数据为: 5子协程ch1写入数据: 5子协程ch1写入数据: 6主协程读取到ch1数据为: 6主协程读取到ch1数据为: 7子协程ch1写入数据: 7子协程ch1写入数据: 8主协程读取到ch1数据为: 8主协程读取到ch1数据为: 9子协程ch1写入数据: 9子协程ch1写入数据: 10主协程读取到ch1数据为: 10读取结束 false主协程读取到ch2数据为: 0子协程ch2写入数据: 0子协程ch2写入数据: 1主协程读取到ch2数据为: 1主协程读取到ch2数据为: 2子协程ch2写入数据: 2子协程ch2写入数据: 3主协程读取到ch2数据为: 3主协程读取到ch2数据为: 4子协程ch2写入数据: 4子协程ch2写入数据: 5主协程读取到ch2数据为: 5主协程读取到ch2数据为: 6子协程ch2写入数据: 6子协程ch2写入数据: 7主协程读取到ch2数据为: 7主协程读取到ch2数据为: 8子协程ch2写入数据: 8子协程ch2写入数据: 9主协程读取到ch2数据为: 9主协程读取到ch2数据为: 10子协程ch2写入数据: 10读取结束 false主协程结束
复制代码

通过上面的代码,我们也发现每个通道都有自己的协程,然后再和主协程进行数据通讯。这样非常的繁琐,很多代码都是重复的。有没有办法实现通道复用呢?

答案是有的。

我们想要实现的效果是使用一个协程处理所有的通道的通讯,这就需要用到 select 关键字,它都能做些什么呢?

接下来,我们通过一端代码了解一下。

代码实例:

package main
import ( "fmt" "time")
func main() { ch1 := make(chan int) ch2 := make(chan int) go func() { for { select { case c1 := <-ch1: fmt.Println("成功获取通道ch1的数据:", c1) case c2 := <-ch2: fmt.Println("成功获取通道ch2的数据:", c2) case <-time.After(time.Second * 2): //使用time.After 设置超时响应。 fmt.Println("超时!!") } } }()
for i := 0; i < 10; i++ { ch1 <- i fmt.Println("通道ch1写入数据:", i) } for i := 0; i < 10; i++ { ch2 <- i fmt.Println("通道ch2写入数据:", i) } time.Sleep(20) // 等待select所在协程执行结束}
复制代码

代码执行结果:

成功获取通道ch1的数据: 0通道ch1写入数据: 0通道ch1写入数据: 1成功获取通道ch1的数据: 1成功获取通道ch1的数据: 2通道ch1写入数据: 2通道ch1写入数据: 3成功获取通道ch1的数据: 3成功获取通道ch1的数据: 4通道ch1写入数据: 4通道ch1写入数据: 5成功获取通道ch1的数据: 5成功获取通道ch1的数据: 6通道ch1写入数据: 6通道ch1写入数据: 7成功获取通道ch1的数据: 7成功获取通道ch1的数据: 8通道ch1写入数据: 8通道ch1写入数据: 9成功获取通道ch1的数据: 9成功获取通道ch2的数据: 0通道ch2写入数据: 0通道ch2写入数据: 1成功获取通道ch2的数据: 1成功获取通道ch2的数据: 2通道ch2写入数据: 2通道ch2写入数据: 3成功获取通道ch2的数据: 3成功获取通道ch2的数据: 4通道ch2写入数据: 4通道ch2写入数据: 5成功获取通道ch2的数据: 5成功获取通道ch2的数据: 6通道ch2写入数据: 6通道ch2写入数据: 7成功获取通道ch2的数据: 7成功获取通道ch2的数据: 8通道ch2写入数据: 8通道ch2写入数据: 9成功获取通道ch2的数据: 9
复制代码

大家看到,上面的代码,我们只通过一个匿名协程就可以处理所有通道的消息,实现了通道的复用。而且整个过程也非常的明确,管理起来也非常方便。

结尾

其实,Golang 的通道的管理是非常复杂的,今后我们在 Golang 的学习过程中,需要重点关注。好了,今天关于通道的介绍就到这里,谢谢大家。


作者简介:😄大家好,我是 Data-Mining(liuzhen007),是一位音视频技术爱好者,前后就职于传统广电巨头和音视频互联网公司,具有丰富的音视频直播和点播相关经验,对 WebRTC、FFmpeg 和 Electron 有非常深入的了解,😄公众号:玩转音视频。同时也是 CSDN 博客专家、华为云社区云享专家、签约作者,欢迎关注我分享更多干货!😄

发布于: 刚刚
用户头像

liuzhen007

关注

敲代码,搞开发。 2021.05.01 加入

本人深耕音视频技术,走全栈路线,前后端通吃,兼顾各端与流媒体服务器。 博客主页地址:https://liuzhen.blog.csdn.net 微信公众号:玩转音视频 欢迎交流学习!

评论

发布
暂无评论
Golang的通道复用上手(三)