go channel
模型https://img2023.cnblogs.com/blog/595074/202312/595074-20231201221342096-710784674.png三部分组成:
发送等待队列
接收等待队列
管道 缓存区定义
在 runtime 的chan.go中
type hchan struct {
qcount uint
dataqsiz uint
buf unsafe.Pointer
elemsize uint16
elemtype *_type // element type
// 上面的这几个组成了一个环形缓存区
closed uint32 // 关闭状态
// 下面4个组成了2个队列 g的
sendx uint // send index
recvx uint // receive index
recvq waitq// list of recv waiters
sendq waitq// list of send waiters
// lock protects all fields in hchan, as well as several
lock mutex// 锁,用于在操作 channel的 元素时候,保证并发安全
}特殊缓存区
https://img2023.cnblogs.com/blog/595074/202312/595074-20231201222419529-704199355.pngqcount已经存储的个数
dataqsiz环形队列缓存的容量,即允许缓存的消息最大个数
buf 指向这个缓存区的地址
elemsize 元素的大小
elemtype元素的类型设计成这样,主要目的不需要gc来清理,因为环形机构,会自动把删除数据内存给占了。
环形缓存可以大幅降低GC的开销
两个队列
https://img2023.cnblogs.com/blog/595074/202312/595074-20231201223331538-870813795.png这里还要看下 waitq 的定义
type waitq struct {
first *sudog
last*sudog
}
// 在sema中也有用到,就g结构体的封装
type sudog struct {
g *g
next *sudog
prev *sudog
elem unsafe.Pointer // 接受参数的地址
// 当是接收g时候,如果有缓存中有数据,直接把数据拷贝到这个地址}
注意:这里的sendx 并不是指向发送队列中的g,而且发送队列应该写入环形缓存区的index,
同理,recvx也是,指向接受数据的g,应该从缓冲区的那个index取数据
互斥锁
lock mutex互斥锁并不是排队发送/接收数据
不是让发送和接收队列来排队的,这些发送和接收数据的队列,休眠也不是在锁的sema里
互斥锁保护的hchan结构体本身
所以, Channel并不是无锁的
状态值
closed uint32 // 关闭状态0为开启、1为关闭
当一个关闭的channel,再往里写或者重复关闭、就会panic。但是可以读。发送数据
c
页:
[1]