一、channel
-
channel 是 golang 提供的语言层面的携程,主要用于进程内部goroutine 之间的通信,跨进程之间的通信还得使用分布式方式来解决。
-
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不允许并发读写 }
-
-
。buf 是环形队列的首地址 。dataqsiz 是队列长度 。qcount 队列还剩余俩个元素的空间 。sendx 3 待写入的数据存储下标位置 。recvx 1 从该位置读取数据 . recvq 从channel读数据的goroutine ,如果缓冲区为空或没有缓冲区,当前goroutine阻塞 。sendq 向channel中写入数据的goroutine,如果缓冲区已满或没有缓冲区,当前goroutine阻塞。 。因读阻塞的goroutine 会被写goroutine唤醒 。因写阻塞的 goroutine会被读goroutine唤醒
-
上图是没有传冲区的channel,一般情况下至少一个为空。当同一个goroutine 使用select同时,读写
-
类型,elemtype 表示数据传递时的数据结构。elemsize表示类型大小
-
锁,lock同时只能被一个goroutine 读写
-
func makechan(t *chantype, size int) *hchan { var c *hchan c = new(hchan) c.buf = malloc(len(chantype) * size) c.elemsize = len(chantype) c.elemtype = chantype c.dataqsiz = size return c } //创建channel的过程c := make(chan int,7)就是初始化hchan的过程
-
-
向channel中写入数据的过程 。 如果缓冲区qcount有空余位置,直接将数据写入缓冲区,结束发送过程 。如果缓冲区没有空余位置,将待发送数据写入G,将当前G加入sendq,进入睡眠,等待G被唤醒 。如果recvq 不为空,说明有多余的G等待读取数据,那么从recvq 中读取一个G 把数据直接吸入G,唤醒G->结束发送 。如果recvq为空,buf不为空时,将G加入sendq等待唤醒;buf为空时,将数据写入 buf对位-> 结束发送
11.从channel读数据[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DvlQ7PFM-1666181905633)(D:\Download\typora\golang\go专家编程\m_933ca9af4c3ec1db0b94b8b4ec208d4b_r.png)]
。如果等待发送队列sendq不为空,且没有缓冲区,直接从sendq取G,把G中数据读出,把G唤醒,结束读取
。如果等待发送队列
- 关闭channel,把recvq 中的G全部唤醒,