Channel

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

waitqsudog 的一个双向链表

1. type waitq struct {
2. first *sudog
3. last *sudog
4. }

sudog 实际上是对 goroutine 的一个封装,表示一个在等待队列中的goroutine,该结构

存储了两个分别指向前后sudog的指针用来构成链表

发送数据
  • 如果当前channel的recvq上存在已经被阻塞的Goroutine(也就是说有goroutine在等待读消息),那么会直接将数据发送给当前的Goroutine并将其设置成下一个运行的Goroutine(设置处理器runnext属性,不会立刻调度)
  • 如果channel存在缓冲区并且还有空余位置,会直接将数据存储到缓存区sendx所在的位置上
  • 如果不满足上述两种情况,会创建一个sudog结构并将其加入channel的sendq队列中,当前Goroutine陷入阻塞等待其他协程从Channel接收数据
接收数据
  • 如果Channel为空,那么会直接让出处理器的使用权。

  • 如果Channel已经关闭并且缓存区没有任何数据,会直接返回

  • 如果Channel的sendq队列中存在挂起的Goroutine(说明有阻塞发送的goroutine),根据缓冲区的大小分别处理不同的情况:

    如果 Channel 不存在缓冲区, 将 Channel 发送队列中 Goroutine 存储的数据拷贝到目标内存地址中;

    如果 Channel 存在缓冲区,将队列中的数据拷贝到接收方的内存地址;将发送队列头的数据拷贝到缓冲区中,释放一个阻塞的发送方;

  • 如果Channel的缓冲区存在数据(没有阻塞的发送Goroutine),会将缓冲区中的数据拷贝到接收方的内存地址、清除队列中的数据并完成收尾工作。

  • 当 Channel 的发送队列中不存在等待的 Goroutine 并且缓冲区中也不存在任何数据时,会使用 runtime.sudog 将当前 Goroutine 包装成一个处于等待状态的 Goroutine 将其加入到接收队列中并陷入休眠等待调度器的唤醒;

关闭通道

当 Channel 是一个空指针或者已经被关闭时,Go 语言运行时都会直接崩溃并抛出异常

处理完了这些异常的情况之后就可以开始执行关闭 Channel 的逻辑了,close 函数先上一把大锁,接着把所有挂在这个 channel 上的 sender 和 receiver 全都连成一个 sudog 链表,再解锁。最后,再将所有的 sudog 全都唤醒。

唤醒之后,sender 会检测到channel已经关闭,panic。从一个有缓冲的 channel 里读数据,当 channel 被关闭,依然能读出有效值。只有当返回的 ok 为 false 时,读出的数据才是无效的,为对应类型的零值。

x, ok := <-ch
产生panic的情况

向一个关闭的 channel 进行写操作;关闭一个 nil 的 channel;重复关闭一个 channel。

总结

channel缓存区是由循环队列实现的

channel的等待队列是一个双向链表

channel 的发送和接收操作本质上都是 “值的拷贝”

从一个有缓冲的 channel 里读数据,当 channel 被关闭,依然能读出有效值。发数据会panic。

详细解读go语言中的chnanel的更多相关文章

  1. 详细解读go语言中的map

    Map map底层是由哈希表实现的 Go使用链地址法来解决键冲突. map本质上是一个指针,指向hmap 这里的buckets就是桶,bmap 每一个bucket最多可以放8个键值对,但是为了让内存排 ...

  2. C语言中的static 详细分析

    转自:http://blog.csdn.net/keyeagle/article/details/6708077/ google了近三页的关于C语言中static的内容,发现可用的信息很少,要么长篇大 ...

  3. 【转载】C语言中的static 详细分析

    原blog地址:http://blog.csdn.net/keyeagle/article/details/6708077/ google了近三页的关于C语言中static的内容,发现可用的信息很少, ...

  4. 转:C语言中的static变量和C++静态数据成员(static member)

    转自:C语言中的static变量和C++静态数据成员(static member) C语言中static的变量:1).static局部变量        a.静态局部变量在函数内定义,生存期为整个程序 ...

  5. C-C++到底支不支持VLA以及两种语言中const的区别

    C-C++到底支不支持VLA以及两种语言中const的区别 到底支不支持VLA VLA就是variable-length array,也就是变长数组. 最近写程序的时候无意间发现,gcc中竟然支持下面 ...

  6. Go语言中slice使用注意事项

    Go 语言中的slice类型可以理解为是数组array类型的描述符,包含了三个因素: 指向底层数组的指针 slice目前使用到的底层数组的元素个数,即长度 底层数组的最大长度,即容量 因此当我们定义一 ...

  7. [转]Go语言中的make和new

    前言 本文主要给大家介绍了Go语言中函数new与make的使用和区别,关于Go语言中new和make是内建的两个函数,主要用来创建分配类型内存.在我们定义生成变量的时候,可能会觉得有点迷惑,其实他们的 ...

  8. C语言中的static关键字

    C语言代码是以文件为单位来组织的,在一个源程序的所有源文件中,一个外部变量(注意不是局部变量)或者函数只能在一个源程序中定义一次,如果有重复定义的话编译器就会报错.伴随着不同源文件变量和函数之间的相互 ...

  9. 关于C语言中的Complex(复数类型)和imaginary(虚数类型)

    关于C语言中的Complex(复数类型)和imaginary(虚数类型) 其实这里的复数complex就是数学里的复数,包含实部和虚部两个部分,比如:x=2.1+6i,下面进行详细介绍. C99 新增 ...

随机推荐

  1. 【动画消消乐 】仿ios、android中常见的一个loading动画 074

    前言 Hello!小伙伴! 非常感谢您阅读海轰的文章,倘若文中有错误的地方,欢迎您指出-   自我介绍 ଘ(੭ˊᵕˋ)੭ 昵称:海轰 标签:程序猿|C++选手|学生 简介:因C语言结识编程,随后转入计 ...

  2. Django < 2.0.8 任意URL跳转漏洞(CVE-2018-14574)

    影响版本 Django < 2.0.8 抓包 访问http://192.168.49.2:8000//www.example.com,即可返回是301跳转到//www.example.com

  3. 终于彻底搞清楚了spin-lock 之一次CPU问题定位过程总结

    首先这个问题,我只是其中参与者之一.但这个问题很有参考意义,特记录下来. 还有我第一次用"彻底"这个词,不知道会不会有人喷?其实,还有一些问题,也不是特别清楚.比如说什么是CPU流 ...

  4. 几个垃圾XSS

    遇见帅比厂商就离谱.... 这个厂商就挖了几个反射XSS,幸亏没有浪费太多时间 嗯 有的有waf.有的没有就离谱 可以看见可以解析的,但是他的这个站,遇见关键函数就自己跳转了.然后去寻找下别的标签fu ...

  5. 乘风破浪,遇见Android Jetpack之Compose声明式UI开发工具包,逐渐大一统的原生UI绘制体系

    什么是Android Jetpack https://developer.android.com/jetpack Android Jetpack是一个由多个库组成的套件,可帮助开发者遵循最佳做法.减少 ...

  6. 痞子衡嵌入式:在IAR开发环境下将关键函数重定向到RAM中执行的三种方法

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是在IAR开发环境下将关键函数重定向到RAM中执行的三种方法. 嵌入式项目里应用程序代码正常是放在 Flash 中执行的,但有时候也需要将 ...

  7. JAVA的一般输入输出 和 快速输入输出 (BufferedReader&BufferedWrite)(转载)

    1.JAVA的一般输入输出 和 快速输入输出 (BufferedReader&BufferedWrite) 摘要 本文主要介绍快速输入输出, 文中提到了几个IO类,这里推荐使用Buffered ...

  8. vue3.0安装

    一 .vue3.0安装 vue3.0安装 个人推荐以下2种 (1). 开发工具的对应代码中 插入CDN <script src="https://unpkg.com/vue@next& ...

  9. Spring学习01(IOC)

    1.Spring概述 简介 2002年,Rod Jahnson首次推出了Spring框架雏形interface21框架. 2004年3月24日,Spring框架以interface21框架为基础,经过 ...

  10. SWAP的罪与罚&&NUMA的取舍

    说个案例:一台Apache服务器,由于其MaxClients参数设置过大,并且恰好又碰到访问量激增,结果内存被耗光,从而引发SWAP,进而负载攀升,最终导致宕机. 正所谓:SWAP,性能之大事,死生之 ...