Go-Channel

Channel知识点目录

简单梳理一下Go中Channel的知识点

一、Channel

Channel介绍:

Channel源于CSP模型,在Go的并发中,提倡使用通信来共享内存而不要使用共享内存来通信。Go内的Channel实现了Goroutine之间的数据的读写操作,在任何时刻,只能有一个Goroutine能对Channel中的数据进行操作,Channel可以看作一个FIFO的消息队列。

Channel的特点:

  • 只能传输一种数据类型
  • chan是引用类型,底层是一个指针。make之后才能使用,如果不make,得到的是nil的chan。初始容量确定后不会再改变
  • 线程安全,无需加锁,Channel结构体会在执行接收操作和发送操作时内部上锁
  • 阻塞操作,缓冲区满时无法再发送数据到chan;缓冲区空时无法再从chan中获取数据

Channel的创建:

ch := make(chan int, 3) // 创建缓冲区大小为3的chan
ch := make(chan int)  // 无缓冲区的chan
var ch chan int // 声明一个chan,但为nill,如果往nill的chan中发送/接收数据会引发deadlock

Channel必须make初始化后才能使用

Channel结构体:hchan

type hchan struct {
 qcount   uint     // 循环队列中元素的个数
 dataqsiz uint    // 循环队列的大小
 buf      unsafe.Pointer // 循环队列中的数据指针
 elemsize uint16   // channel中元素的大小
 closed   uint32   // channel是否关闭
 elemtype *_type   // channel中的元素类型
 
 sendx    uint   // 往chan中发送数据chan<-,在buf中的位置
 recvx    uint   // 从chan中取出数据<-chan,在buf中的位置
 recvq    waitq   // g想执行<-chan操作接收数据时,如果chan无数据,会被放入recvq中
 sendq    waitq   // g想执行chan<-操作发送数据时,如果chan已经满,会被仿佛sendq中
 
 lock mutex    // 互斥锁,用于保护所有字段
}

二、sendqrecvq 的作用

我们通过ch := make(chan int, 3)创建一个缓冲区大小为3的chan。我们有一个Goroutine,简称为G1

sendq

  • 在G1中执行三次ch <-1的操作后,chan缓冲区已满

  • 然后G1还想执行一次ch<-value的操作时,因为缓冲区已满,无法再发送数据进chan中,因此G1执行gopark主动调用Go的调度器scheduler,让出与G1绑定的M

  • G1会抽象成一个包含指向G1的指针以及包含value元素的sudog结构体,然后存放在sendq中等待被唤醒

    唤醒时机:当另一个Goroutine,假设为G2,想从chan中获得数据时,G2执行<-ch操作,从缓存队列中取出数据
    唤醒方式:channel会将G1的sudog结构体取出并且将value数据放进缓存队列中,然后唤醒G1,放回可执行队列中

recvq

  • 在G1中直接从刚初始化的chan中执行接收数据的操作<-ch
  • 此时chan中没有任何数据,那么G1会阻塞,G1调用gopark调用scheduler,让出与G1绑定的M,使M可以和其他G绑定
  • G1会抽象成一个包含指向G1的指针以及空元素的sudog结构体,然后存放在recvq中等待被唤醒

唤醒时机:当有另外一个Goroutine,假设为G2,想往chan中发送数据时,G2执行ch<-操作,往缓存队列中发送数据
唤醒方式(与sendq中的唤醒方式不同!!):G2并没有锁住chan把数据放在缓存队列中,而是直接把数据copy到了G1中,减少了内存的拷贝以及加锁释放锁的时间花费。最后唤醒G1,放回可执行队列中

三、不同情况下Channel的<-chch<-操作

无缓冲Chan

<-ch:阻塞
ch<-:阻塞

有缓冲Chan

<-ch:缓冲区中存在数据,不阻塞;缓冲区无数据,阻塞
ch<-:缓冲区中数据未满,不阻塞;缓冲区中数据已满,阻塞

已关闭的Chan

<-ch:如果Chan中还有数据没有读取,则返回数据和数据是否有效的bool;如果没有数据,则返回0值和false
ch<-:panic
重复关闭已关闭的Chan:panic

nil Chan

<-ch:死锁
ch<-:死锁
关闭nill Channel:panic

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值