

go的channel源码层理解 - 无远弗届
source link: http://cbsheng.github.io/posts/go%E7%9A%84channel%E6%BA%90%E7%A0%81%E5%B1%82%E7%90%86%E8%A7%A3/?
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

go的channel源码层理解
基于源码1.9.3
Go中的channel分为了带buffer和无buffer的。
带buffer的,底层是用了一个循环数组,消息加到数组的最后就会折返到数组的开始。数组满了的时候,就会阻塞发送操作。
无buffer的,底层就不依赖数组了。因为在无buffer的channel上收发消息行为是会直接阻塞的,这种情况处理不妥善会出现死锁问题。一般可以先把读channel读的goroutine先启动起来,再启动写channel。
|
|
当不能继续发送或读取时,就会出现阻塞。具体动作是把当前的goroutine挂起,挂到channel上。而channel是一个结构体(下文配源码)。里面有两个指针(recvq和sendq),分别指向阻塞读和阻塞写的goroutine队列。
在channel上发送和读取消息的逻辑有点不一样。
发送消息时:
- channel已经关闭,那就不能发。panic掉。
- 看一下有没有阻塞在读操作上的goroutine,有的话,赶紧把数据复制给它。把它安排在下一次调度切换上。(p.runnext)
- 没有被阻塞的goroutine。如果带buffer,buffer还有空位,就放在buffer里。否则就阻塞挂起当前发送消息的goroutine。
所以要注意,不要依赖发送到channel的顺序。发送消息时遇到被阻塞读操作的goroutine时,会先满足它们,即使buffer里还有数据。
读取消息时:
- channel已经关闭,也可以读,只是读出来的数据为空。
- 看一下有没有阻塞的写操作的goroutine,有的话唤醒它。读取它发送的数据(A)。
- 读取后的数据(A)放哪,视乎是带buffer还是无buffer。无buffer的话,就直接把写数据(A)给读取者。带buffer的话,就先看buffer里是否有数据(B),有就把数据(B)给读取者,再把数据(A)放到原来数据(B)空出来的位置上。
整个读写过程,都是需要加锁的。毕竟channel是在多个goroutine中被使用。
此外,无论是带buffer或无buffer,数据在 发送者-buffer-读取者 三者流转时。都是采用拷贝的方式(typedmemmove)。这也呼应了go里不存引用传递,都是值传递。所以使用channel时,避免使用过大的数据。而且要改变从channel里读取出来的值时,channel的类型要使用指针类型。
Go提倡通过通信来共享内存,而非通过共享内存来通信,正是使用了channel来达到这个效果。这个就是Hoare提出的CSP(Communicating Sequential Processes)。这种方式也在Occam和Erlang上进行了验证,是没问题的。所以Go也使用上。
了解原理后,会发现channel底层还是用了锁。但channel提供给开发者是一种更高层的并发编程思维和用法,它更易用和直接,减少bug。而非pthread那种基于信号量,锁等较底层的并发编程方式。
channel的数据结构
|
|
通过channel写数据
|
|
通过channel读数据
|
|
recvDirect和sendDirect
|
|
Recommend
-
66
channel是大家在Go中用的最频繁的特性,也是Go最自豪的特性之一,你有没有思考过: Why:为什么要设计channel? What:channel是什么样的? How:channel是如何实现的? 这篇文章...
-
35
-
32
-
72
-
40
Redis(5.0.3)内存淘汰LRU/LFU redis的LRU与LFU都是概率算法。并不是绝对准确的LRU或LFU算法。
-
50
golang标准库sync.Pool原理及源码简析 pool关键作用: 减轻GC的压力。 复用对象内存。有时不一定希望复用内存,单纯是想减轻GC压力也可主...
-
50
原文作者:shitaibin channel是大家在Go中用的最频繁的特性,也是Go最自豪的特性之一,你有没有思考过: Why:为什...
-
20
点击上方蓝色“ Go语言中文网 ”关注我们, 领全套Go资料 ,每天学习 Go 语言
-
8
观点 酷开网络年度盘点:距离OTT无远弗届的梦想,又近了一小步 电科技袁创12-31 19:15 161 2020年的OTT行业加速向前。 持续高增长的OTT行业在今...
-
1
go的channel源码层理解 June 2, 2019 Golang
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK