Golang中channel的实现

1、channel的基本概念

channel俗称管道,用于数据传递或数据共享,其本质是一个先进先出的队列,使用goroutine+channel进行数据通讯简单高效,同时也线程安全,多个goroutine可同时修改一个channel,不需要加锁。

channel可分为三种类型:

  1. 只读channel:只能读channel里面数据,不可写入
  2. 只写channel:只能写数据,不可读
  3. 一般channel:可读可写

2、channel的数据结构

type hchan struct {
    qcount uint // 队列中元素个数 
    dataqsiz uint // 循环队列的大小 
    buf unsafe.Pointer // 指向循环队列 
    elemsize uint16 // 通道里面的元素大小 
    closed uint32 // 通道关闭的标志 
    elemtype *_type // 通道元素的类型 
    sendx uint // 待发送的索引,即循环队列中的队尾指针front 
    recvx uint // 待读取的索引,即循环队列中的队头指针rear 
    recvq waitq // 接收等待队列 
    sendq waitq // 发送等待队列 
    lock mutex // 互斥锁 
}

3、channel的hchan结构

        hchan结构体中的buf指向一个数组,用来实现循环队列,sendx是循环队列的队尾指针,recvx是循环队列的队头指针。dataqsize是缓存型通道的大小,qcount是记录通道内元素个数。 

        循环队列一般使用空余单元法来解决队空和队满时候都存在font=rear带来的二义性问题,但这样会浪费一个单元。golang的channel中是通过增加qcount字段记录队列长度来解决二义性,一方面不会浪费一个存储单元,另一方面当使用len函数查看队列长度时候,可以直接返回qcount字段,一举两得。 

        hchan结构体中另一重要部分是recvq,sendq,分别存储了等待从通道中接收数据的goroutine,和等待发送数据到通道的goroutine两者都是waitq类型。sudog是对goroutine的一种封装

type waitq struct {

    first *sudog

    last *sudog

}

        waitq是一个结构体类型,waitq和sudog构成双向链表,其中sudog是链表元素的类型,waitq中first和last字段分别指向链表头部的sudog,链表尾部的sudog。

        channel 的发送和接收操作本质上都是 “值的拷贝”,无论是从 sender goroutine 的栈到 chan buf,还是从 chan buf 到 receiver goroutine,或者是直接从 sender goroutine 到 receiver goroutine。 

4、channel的读写流程

channel读取写入流程
操作nil channelclosed channelnot nil,not closed

close

panic

panic

正常关闭

读<-ch

阻塞

如果channel关闭前有数据,则会正常读取到数据.如果没有数据则会读取到对应元素类型的空值

阻塞或正常读取数据,缓冲型channel为空或非缓冲型channel等待发送者时会阻塞

写ch<-

阻塞

panic

阻塞或正常写入数据,非缓冲型channel等待接收者或缓冲型channel buf满时会被阻塞

channel的写流程 

 channel的读流程 

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值