Hello,大家好,又见面了!上一遍我们将 channel 相关基础以及使用场景 。这一篇,还需要再次进阶理解channel 阻塞问题 。以下创建一个chan类型为int,cap 为3 。
ch := make(chan string,1)
channel 内部其实是一个环形buf数据结构,是一种滑动窗口机制,当make完后,就分配在 Heap 上 。
Channel 是如何发送数据和接收数据,会有什么问题出现,面试也是常见 。设 G1 为发送者:
ch <- "hello"
上面,向 chan 发送一条“hello”数据:- 第一步: acquire lock
- 第二步:enqueue(把“hello”拷贝buf数组里)
- 第三步:release lock
看下面实例:
ch := make(chan int,1)ch <- 100ch <- 200
以上会出现什么,chan 缓冲区允许大小为1,如果再往chan仍数据,满了就会被阻塞,那么是如何实现阻塞的呢?当 chan 满时,会进入 gopark,此时 G1 进入一个 waiting 状态,然后会创建一个 sudog 对象,其实就sendq队列,把 200放进去 。等 buf 不满的时候,再唤醒放入buf里面 。通过如下源码,你会更加清晰:
type hchan struct {//省略部分代码 。。。recvqwaitq// list of recv waiterssendqwaitq// list of send waiters//省略部分代码 。。。}type waitq struct {first *sudoglast*sudog}type sudog struct {g *gnext *sudogprev *sudogelem unsafe.Pointer // data element (may point to stack)acquiretime int64releasetime int64ticketuint32isSelect boolsuccess boolparent*sudog // semaRoot binary treewaitlink *sudog // g.waiting list or semaRootwaittail *sudog // semaRootc*hchan // channel}
设 G2 为接收者:d := <- ch
上面,从 chan 获取数据:- 第一步:也是先获取锁
- 第二步:从 buf 数据里面拷贝,赋给 d 变量
- 第三步:release lock
如果接收者,接收一个空对象,也会发生什么情况?
代码示例:
ch := make(chan int,1)t := <- ch
也会报错如下:fatal error: all goroutines are asleep - deadlock!
上面,从 chan 取出数据,可是没有数据了 。此时,它会把 接收者 G2 阻塞掉,也是和G1发送者一样,也会执行 gopark 将状态改为 waiting,不一样的点就是 。正常情况下,接收者G2作为取出数据是去 buf 读取数据的,但现在,buf 为空了,此时,接收者G2会将sudog导出来,因为现在G2已经被阻塞了嘛,会把G2给G,然后将t := <-ch中变量 t 是在栈上的地址,放进去elem,也就是说,只存它的地址指针在sudog里面 。
最后,ch <- 200 当G1往 chan 添加200这个数据,正常情况是将数据添加到buf里面,然后唤醒 G2 是吧,而现在是将 G1 的添加200数据直接干到刚才G2阻塞的t这里变量里面 。
【Go 语言 channel 的阻塞问题】你会认为,这样真的可以吗?想一想,G2 本来就是已经阻塞了,然后我们直接这么干肯定没有什么毛病,而且效率提高了,不需要再次放入buf再取出,这个过程也是需要时间 。不然,不得往chan添加数据需要加锁、拷贝、解锁一序列操作,那肯定就慢了,我想Go语言是为了高效及内存使用率的考虑这样设计的 。(注意,一般都是在runtime里面完成,不然会出现象安全问题 。)
总结:
chan 类型的特点:chan 如果为空,receiver 接收数据的时候就会阻塞等待,直到 chan 被关闭或者有新的数据到来 。有这种个机制,就可以实现 wait/notify 的设计模式 。
使用 channel 要思考的问题?
- 如果N个发送者发送到chan及N个接收者,这样会频繁导致锁频繁争用;
- 如果N个往 chan 发送,而 buf很小,会导致 Goroutine 不断被gopark,然后runtime开销就大了;
- channel 有缓冲区和无缓冲区别?
- channel 线程安全吗?
- 是否了解 channel 底层实现,比如channel 底层数据结构?环形buf
推荐阅读
- 英九红茶历史,推荐个红茶的店铺
- 红茶文化历史,遵义红茶的起源
- 功夫红茶属于滇红茶吗,功夫红茶历史
- 阿萨姆红茶的历史,阿萨姆红茶泡法
- 信阳红茶历史,遵义红茶的起源
- 锡兰红茶的历史,锡兰红茶怎么煮
- 土耳其红茶的作用,红茶在土耳其的历史
- 全职妈妈|让很多人误解的职业
- |案例:一起因偷看女邻居洗澡引发的血案
- |职场人际套路多,同事间关系再好,也难成为真正的朋友