golang源码分析:channel

本文详细分析了Golang中channel的主要结构,包括环形数组队列、goroutine等待队列和互斥锁。阐述了channel的make、send、receive和close操作的实现细节,如send时的阻塞条件、close后的处理等,并强调了仅发送端能关闭channel,重复关闭或关闭nil channel会导致panic。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先说一些结论:只有发送端可以close chan,接收端不要搞

1、重复 close,产生 panic

2、close一个nil,产生 panic

3、写未初始化chan永远阻塞

4、写close会panic

5、make chan返回的是* hchan,所以chan可以随意在函数和go间传递

 

channel 的主要结构:

一个环形数组实现的队列,用于存储消息元素;

两个链表实现的 goroutine 等待队列,用于存储阻塞在 recv 和 send 操作上的 goroutine;

一个互斥锁,用于各个属性变动的同步

channel make 实现

当元素不含指针的时候,会将整个 hchan 分配成一个连续的空间。

channel send

send 有以下几种情况:

  • 写未初始化chan永远阻塞,写close会panic
  • 有 goroutine 阻塞在 channel recv 队列上,此时缓存队列为空,直接将消息发送给 reciever goroutine,只产生一次复制
  • 当 channel 缓存队列有剩余空间时,将数据放到队列里,等待接收,接收后总共产生两次复制
  • 当 channel 缓存队列已满时,将当前 goroutine 加入 send 队列并阻塞。

 

channel recieve

  • 从已经 close 且为空的 channel recv 数据,返回空值及false
  •  
  • send 队列不为空
  1. 缓存队列为空(证明是无缓冲chan),直接从 sender recv 元素
  2. 缓存队列不为空,此时只有可能是缓存队列已满,从队列头取出元素,并唤醒 sender 将元素写入缓存队列尾部
  • 缓存队列不为空,直接从队列取元素,移动头索引(cnt- -, recv++)
  • 缓存队列为空,将 goroutine 加入 recv 队列,并阻塞

channel close

  • 重复 close,产生 panic
  • 唤醒所有 reciever, (这里被唤醒的go会去读channel,然后get到空值及false)
  • 唤醒所有 sender(理论上不可能有,so),产生 panic

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值