一、channel

  1. channel 是 golang 提供的语言层面的携程,主要用于进程内部goroutine 之间的通信,跨进程之间的通信还得使用分布式方式来解决。
  2. 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唤醒

go语言 通道缓冲 golang通道底层_数据结构

  1. 上图是没有传冲区的channel,一般情况下至少一个为空。当同一个goroutine 使用select同时,读写
  2. 类型,elemtype 表示数据传递时的数据结构。elemsize表示类型大小
  3. 锁,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唤醒,结束读取
。如果等待发送队列
  1. 关闭channel,把recvq 中的G全部唤醒,