当前位置: 首页 > news >正文

聊聊go语言channel中的一些小技巧

写在文章开头

go语言提供了各种非常方便的语法糖,使得我们实现用最少的语法做尽可能高效的事情,而本文就简单介绍如何实现非阻塞处理多个channel,希望对你有帮助。

Hi,我是 sharkChili ,是个不断在硬核技术上作死的技术人,是 CSDN的博客专家 ,也是开源项目 Java Guide 的维护者之一,熟悉 Java 也会一点 Go ,偶尔也会在 C源码 边缘徘徊。写过很多有意思的技术博客,也还在研究并输出技术的路上,希望我的文章对你有帮助,非常欢迎你关注我的公众号: 写代码的SharkChili

因为近期收到很多读者的私信,所以也专门创建了一个交流群,感兴趣的读者可以通过上方的公众号获取笔者的联系方式完成好友添加,点击备注 “加群” 即可和笔者和笔者的朋友们进行深入交流。

在这里插入图片描述

详解channel非阻塞技巧

假设我们现在有这样一个需求,有个有缓冲区bufferedChannel和无缓冲区noBufferChannel,我们希望用一个协程做到查看无缓冲区channel没数据时,再处理有缓冲区channel

对此,我们先介绍一下select语法,按照其工作原理可知,只要某个case无法满足要求就会走到下一个case,由此我们不妨做个猜测,由此我们是否可以将channel的收发作为case分支做到分支1的channel无法处理时执行分支2逻辑呢?

在这里插入图片描述

对此我们给出这样一段代码,可以看到笔者声明了有缓冲区channel1和无缓冲区chann2,然后向有缓冲区chan1投递数据,进而走到select分支。
重点来了,按照正常逻辑,noBufferChannel 是无缓冲区,投递数据1应该阻塞等待消费才对,但是在select分支语法下,在noBufferChannel 数据投递失败之后,走到了下一个分支,该分支的channel收到上文投递的数据1,直接步入逻辑完成打印:

func main() {//创建两个channelnoBufferChannel := make(chan int)bufferedChannel := make(chan int, 1)//往有缓冲区channel中投递数据,因为有缓冲区,数据投递到缓冲区后,逻辑继续向下bufferedChannel <- 1//通过select语法避免无缓冲区chan2数据没有被及时消费而阻塞select {case noBufferChannel <- 1:log.Println("无缓冲区channel逻辑执行了")case num := <-bufferedChannel:log.Println("有缓冲区channel收到数据了:", num)default:log.Println("defult logic")}
}

对应输出结果如下:

 有缓冲区channel收到数据了: 1

由此我们可知,通过select语句,可以非阻塞的执行每一个case逻辑,以本文代码为例,无缓冲区channelcase逻辑发现数据无法投递时,则走到下一个分支查看是否可以执行,结果有缓冲区channel有数据,最终非阻塞走到分支2完成逻辑执行:

在这里插入图片描述

实际上,go语言做到更强大的优化,假如上文两个channel的逻辑都无法执行且没有default分支,它会将这个协程分别注册到所有channel的阻塞队列中,只要某个channel具备处理条件,就会唤醒对应分支。

对应的我们给出这样一个select实现非阻塞轮询的例子,子协程非阻塞轮询所有channel,发现channel都不具备处理的条件,于是将该协程存到各个channel的阻塞队列中。随后主协程消费无缓冲区队列的数据,唤醒无缓冲区的case逻辑:

在这里插入图片描述

对应我们给出示例代码:

func main() {var wg sync.WaitGroupwg.Add(1)//创建两个channelnoBufferChannel := make(chan int)bufferedChannel := make(chan int, 1)go func() {log.Println("子协程执行,发现无法执行后阻塞")defer wg.Done()//通过select语法避免无缓冲区chan2数据没有被及时消费而阻塞select {case noBufferChannel <- 1:log.Println("无缓冲区channel逻辑执行了")case num := <-bufferedChannel:log.Println("有缓冲区channel收到数据了:", num)}}()//休眠1s等待协程1执行完成time.Sleep(1 * time.Second)log.Println("主协程消费数据")num := <-noBufferChannelwg.Wait()log.Println("执行结束,num:", num)}

小结

以上便是笔者对于go语言channel非阻塞的工作机制和使用分析,希望对你有帮助。

我是 sharkchiliCSDN Java 领域博客专家mini-redis的作者,我想写一些有意思的东西,希望对你有帮助,如果你想实时收到我写的硬核的文章也欢迎你关注我的公众号: 写代码的SharkChili
因为近期收到很多读者的私信,所以也专门创建了一个交流群,感兴趣的读者可以通过上方的公众号获取笔者的联系方式完成好友添加,点击备注 “加群” 即可和笔者和笔者的朋友们进行深入交流。

在这里插入图片描述


http://www.mrgr.cn/news/22587.html

相关文章:

  • 数字电子技术-波形图
  • C语言-qosrt函数—秩序大师
  • Maven项目父模块POM中是否应该包含SpringBoot打包插件(spring-boot-maven-plugin)
  • [苍穹外卖]-06微信登录详解
  • 基于ONSEMI电源管理芯片NCP1607之AC300V高输入电压36W调色温智能电源
  • Windows Docker 部署 HertzBeat 实时监控告警系统
  • Oracle(113)什么是全备份(Full Backup)?
  • golang学习笔记12——Go 语言内存管理详解
  • ios 项目中设置左侧徽标
  • linux运维常见命令行
  • 绿光扫码激光器定制多少钱?费用决定因素
  • 数据资产:新时代的财富密码
  • 长文本分块的新策略——后期分块(Late Chunking),让RAG应用“又准又高效“
  • 《数字图像处理(面向新工科的电工电子信息基础课程系列教材)》Chapter 1课件2024
  • Spring Boot 常用注解详解
  • LeetCode题练习与总结:最大正方形--221
  • 解决VSCode保存后未格式化文档的问题
  • Android Graphics 显示系统 - 图层的生命周期 Layer Lifecycle
  • 生成单据的流水号
  • AI一键生成 PPT