目录

  • channel背景

  • channel基本用法

  • channel应用场景

  • channel实现原理

    • channel数据结构

    • channel实现方式

  • channel注意事项

  • 闲聊

  • 欢迎加入我的公众号【迈莫coding】 一起pk大厂

1channel背景

channel是Go的核心类型,是Go语言内置的类型,你无需引包,就能使用它。你可以把它看作一个管道,在Go语言中流传着一句话,"执行业务处理的goroutine不要通过共享内存通信,要通过channel管道进行共享数据"

channel和Go的另一种特性goroutine一起为并发编程提供了优雅的,便利的方案,来应对并发场景。

2channel基本用法

channel的基本用法非常简单,它提供了三种类型,分别为只能接收只能发送既能接收也能发送这三种类型。因此它的语法为:

chanstruct{} chan chan string // 既能接收也能发送

我们把既能发送也能接收的chan被称为双向chan,把只能接收或者只能发送的chan称为单向chan。其中,"这个箭头总是射向左边的,元素类型总在最右边。如果箭头指向 chan,就表示可以往 chan 中塞数据;如果箭头远离 chan,就表示 chan 会往外吐数据。

通过make关键字,我们可以初始化一个chan,未初始化的chan的零值为nil。你可以设置他的容量,第二个参数为缓冲池的容量大小,也可以理解为即使chan未消费完,也可以存储数据。

make(chan int, 8)
 

如果chan中还有数据,那么从这个chan中接收数据就不会阻塞,如果chan中数据未达到队列容量,那么向该chan中存储数据也不会阻塞,反之会阻塞。

还有一个知识点要记住:nil 是 chan 的零值,是一种特殊的 chan,对值是 nil 的 chan 的发送接收调用者总是会阻塞。

接下来,我们用代码来学习一下chan的三种类型

  • 只能接收数据的chan

代码示例

package main import "fmt"// a 表示只能接收数据的chanfunc goChanA(a chan int) {  b :=   fmt.Println("只能接收数据的channal[a]接收到的数据值为", b)}func main() {  ch := make(chan int, 2)  go goChanA(ch)  // 往ch中写入数据值  ch 2  time.Sleep(time.Second)}

结果

只能接收数据的channal[a]接收到的数据值为 2
 
  • 只能发送数据的chan

代码示例

package main import "fmtfunc main() {  ch := make(chan  ch }

往 chan 中发送一个数据使用“ch

这里的 ch 是 chan int 类型或者是 chan

3channel应用场景

  • 数据交流:当作并发的 buffer 或者 queue,解决生产者 - 消费者问题。多个 goroutine 可以并发当作生产者(Producer)和消费者(Consumer)。

  • 数据传递:一个goroutine将数据交给另一个goroutine,相当于把数据的拥有权托付出去。

  • 信号通知:一个goroutine可以将信号(closing,closed,data ready等)传递给另一个或者另一组goroutine。

  • 任务编排:可以让一组goroutine按照一定的顺序并发或者串行的执行,这就是编排功能。

  • 锁机制:利用channel实现互斥机制。

4channel实现原理

channel数据结构

channel一个类型管道,通过它可以在goroutine之间发送消息和接收消息。它是golang在语言层面提供的goroutine间的通信方式。

众所周知,Go依赖于称为CSP(Communicating Sequential Processes)的并发模型,通过 Channel实现这种同步模式。

channel结构体

//path:src/runtime/chan.gotype hchan struct {  qcount uint          // 当前队列列中剩余元素个数  dataqsiz uint        // 环形队列长度,即可以存放的元素个数  buf unsafe.Pointer   // 环形队列列指针  elemsize uint16      // 每个元素的⼤⼩  closed uint32        // 标识关闭状态  elemtype *_type      // 元素类型  sendx uint           // 队列下标,指示元素写⼊入时存放到队列列中的位置 x  recvx uint           // 队列下标,指示元素从队列列的该位置读出    recvq waitq          // 等待读消息的goroutine队列  sendq  waitq         // 等待写消息的goroutine队列  lock mutex           // 互斥锁,chan不允许并发读写}

从数据结构可以看出channel由队列、类型信息、goroutine等待队列组成。

channel实现方式

chan内部实现了一个缓冲队列作为缓冲区,队列的长度是创建chan时指定的。

下图展示了可缓存6个元素的channel示意图:

  • dataqsiz:指向队列的长度为6,即可缓存6个元素

  • buf:指向队列的内存,队列中还剩余两个元素

  • qcount:当前队列中剩余的元素个数

  • sendx:指后续写入元素的位置

  • recvx:指从该位置读取数据

等待队列

从channel中读数据,如果channel缓冲区为空或者没有缓冲区,当前goroutine会被阻塞;向channel中写数据,如果channel缓冲区已满或者没有缓冲区,当前goroutine会被阻塞。

被阻塞的goroutine将会被挂在channel的等待队列中:

  • 因读阻塞的goroutine会被向channel写入数据的goroutine唤醒

  • 因写阻塞的goroutine会被从channel读数据的goroutine唤醒

下面展示了一个没有缓冲区的channel,有几个goroutine阻塞等待数据:

注意,一般情况下recvq和sendq至少有一个为空。只有一个例外,那就是同一个goroutine使用select语句向channel一边写数据一边读数据。

向channel写数据

  • 流程图:

  • 详细过程

    • 如果recvq队列不为空,说明缓冲区没有数据或者没有缓冲区,此时直接从recvq等待队列中取出一个G,并把数据写入,最后把该G唤醒,结束发送过程;

    • 如果缓冲区有空余位置,则把数据写入缓冲区中,结束发送过程;

    • 如果缓冲区没有空余位置,则把数据写入G,将当前G写入sendq队列,进入休眠,等待被读goroutine唤醒;

从channel读数据

  • 流程图

  • 详细过程

    • 如果等待发送队列sendq不为空,且没有缓冲区,直接从sendq队列中取出G,把G中数据读出,最后把G唤醒,结束读取过程;

    • 如果等待发送队列sendq不为空,说明缓冲区已满,从缓冲队列中首部读取数据,从sendq等待发送队列中取出G,把G中的数据写入缓冲区尾部,结束读取过程;

    • 如果缓冲区中有数据,则从缓冲区取出数据,结束读取过程;

5channel注意事项

  • 向已经关闭的channel中写入数据会发生Panic

  • 关闭已经关闭的channel会发生Panic

  • 关闭值为nil的channel会发生Panic

6闲聊

  • 读完文章,自己是不是和channel管道的cp率又提高了

  • 我是迈莫,欢迎大家和我交流

原创不易,觉得文章写得不错的小伙伴,点个赞? 鼓励一下吧~

7欢迎加入我的公众号【迈莫coding】 一起pk大厂

  • 迈莫coding欢迎客官的到来

channelinactive触发后不关闭channel_go那些事儿|channel使用及其实现原理相关推荐

  1. channelinactive触发后不关闭channel_Go语言 | goroutine不只有基础的用法,还有这些你不知道的操作...

    今天是golang专题第15篇文章,我们来继续聊聊channel的使用. 在我们的上篇文章当中我们简单介绍了golang当中channel的使用方法,channel是golang当中一个非常重要的设计 ...

  2. channelinactive触发后不关闭channel_golang chan 最详细原理剖析,全面源码分析!看完不可能不懂的!...

    大纲 channel 是什么? channel 使用姿势 chan 创建 chan 入队 chan 出队 结合 select 语句 结合 for-range 语句 源码解析 `makechan` hc ...

  3. IPC3A5I-FW电瓶车入梯检测触发后电梯门依旧会关闭

    IPC3A5I-FW电瓶车入梯检测触发后电梯门依旧会关闭 一.组网 IPC3A5I-FW开启入梯检测报警,并报警输出连接到电梯 二.问题描述 IPC3A5I-FW配置电瓶车入梯检测报警后,联动声光报警 ...

  4. layui.open 关闭之后触发_JAVA虚拟机关闭钩子(Shutdown Hook)

    前言 当你认真的去看一个组件的源码的时候,你会经常看见这种关闭钩子的函数,如果你不了解的话,谷歌一下,你就会发现如下文章就是搜索引擎出来的第一篇,不愧是出自我们优秀的厮哒哒之笔. 正文 Java 程序 ...

  5. Angular指令 - 何时以及如何使用编译,控制器,预链接和后链接[关闭]

    本文翻译自:Angular directives - when and how to use compile, controller, pre-link and post-link [closed] ...

  6. XP中怎样让批处理文件运行后,不关闭dos窗口

    BAT文件最后加一行:pause 因为双击运用结束后就关闭界面了 ====== 在BAT文件后面加上CMD就行了 你看看BAT最后面几行有没有类似EXIT的命令,如果有,删除掉把CMD加上,或在EXI ...

  7. octave绘制图片Figure后无法关闭

    环境: ubuntu18.10-64位 Octave4.4-64位 问题重新: 绘制图片后无法关闭. 核心思想就是更换图片绘制工具, 把stackoverflow上面的答案粘贴如下: ######## ...

  8. 关于Windows 1803版本内核隔离打开后无法关闭的解决方案

    关于Windows 1803版本内核隔离打开后无法关闭的解决方案 参考文章: (1)关于Windows 1803版本内核隔离打开后无法关闭的解决方案 (2)https://www.cnblogs.co ...

  9. win10 更新1809版后彻底关闭系统自动更新的方法

    win10 更新1809版后彻底关闭系统自动更新的方法 win10 升级到1809版后,多了一个"Windows Update Medic Service"服务,该服务是" ...

最新文章

  1. AliCloudDB for redis应用场景之存储最新N条聊天记录
  2. Elasticsearch之Mapping Meta-Fields
  3. python小知识点
  4. 【SQL进阶】03.执行计划之旅1 - 初探
  5. 工作和人工智能的未来
  6. Hive的基本操作-基本查询语法
  7. python迷宫起点终点所有路径_通向终点的路不止一条!python迷宫。
  8. 【Kafka】KafkaConnection to 1002 was disconnected before the response was read
  9. stl:string:将str中的oldstr替换为newstr
  10. 数据挖掘的步骤有哪些
  11. 由jar文件生成jad文件
  12. wget: unable to resolve host address的解决方法
  13. win10安装双系统
  14. java 比较源文件_Beyond Compare比较Java源代码文件的详细操作方法
  15. mpeg2是信源还是信道编码_11.2、11.3信源及信道编码.ppt
  16. ngx-datatable中文教程
  17. 15nm粒径球形纳米金AuNPs-Thrombin修饰R-藻红蛋白/阿霉素的制备过程
  18. Ubuntu 安装及基本配置(显示、镜像源、网络配置)
  19. linux常用命令:文本编辑
  20. AVS3码流结构解析

热门文章

  1. vue调用百度地图API
  2. Ajax — 第一天
  3. 老男孩Day1作业(一):编写登录接口
  4. 用PHP和Websocket实现实时通讯
  5. java.net.SocketException: Permission denied解决
  6. c#中使用ref和out传值
  7. 基于Google Reader发展起来的个性化推荐系统之三大问题
  8. zookeeper入门系列
  9. Python数据分析之pandas入门
  10. 学界 | CVPR 2018颁布五大奖项,何恺明获年轻学者奖