前言
面试被问到好几次“channel是如何实现的”,我只会说“啊,就一块内存空间传递数据呗”…所以这篇文章来深入学习一下Channel相关。从源码开始学习其组成、工作流程及一些常见考点。
NO!共享内存
Golang的并发哲学是“不要通过共享内存的方式进行通信,而是应该通过通信的方式共享内存。”
共享内存会需要使用锁、信号量等方式去控制访问,保障内存的一致性。所以会导致性能损耗+同步问题复杂。
“通过通信来共享内存”的理念强调在并发单元之间通过消息传递来交换数据,而不是直接共享内存。这样,每个并发单元都有自己的内存,不与其他并发单元共享。当它们需要共享数据时,它们会通过发送消息来完成。这种方法的优点是避免了使用锁和同步机制,从而降低了死锁和竞态条件的风险,简化了并发程序的设计和理解。
Channel整体结构
源码位置
位于src/runtime下的chan.go中。

Channel整体结构图
图源:https://i6448038.github.io/2019/04/11/go-channel/

Channel结构体
type hchan struct {
qcount uint // total data in the queue
dataqsiz uint // size of the circular queue
buf unsafe.Pointer // points to an array of dataqsiz elements
elemsize uint16
closed uint32
elemtype *_type // element type
sendx uint // send index
recvx uint // receive index
recvq waitq // list of recv waiters
sendq waitq // list of send waiters
// lock protects all fields in hchan, as well as several
// fields in sudogs blocked on this channel.
//
// Do not change another G's status while holding this lock
// (in particular, do not ready a G), as this can deadlock
// with stack shrinking.
lock mutex
}
我们可以看到,其中有一个buf空间,这个对应的是我们生成的有缓冲通道、无缓冲通道。recvq和sendq对应的是waitq类型,其中主要存储的是发送、接受方的Goroutine。
waitq&&sudog
waitq:
type waitq struct {
first *sudog
last *sudog
}
sudog:
// sudogs are allocated from a special pool. Use acquireSudog and
// releaseSudog to allocate and free them.
type sudog struct {
// The following fields are protected by the hchan.lock of the
// channel this sudog is blocking on. shrinkstack depends on
// this for sudogs involved in channel ops.
g *g
next *sudog
prev *sudog
elem unsafe.Pointer // data element (may point to stack)
// The following fields are never accessed concurrently.
// For channels, waitlink is only accessed by g.
// For semaphores, all fields (including the ones above)
// are only accessed when holding a semaRoot lock.
acquiretime int64
releasetime int64
ticket uint32
// isSelect indicates g is participating in a select, so
// g.selectDone must be CAS'd to win the wake-up race.
isSelect bool
// success indicates whether communication over channel c
// succeeded. It is true if the goroutine was awoken because a
// value was delivered over channel c, and false if awoken
// because c was closed.
success bool
parent *sudog // semaRoot binary tree
waitlink *sudog // g.waiting list or semaRoot
waittail *sudog // semaRoot
c *hchan // channel
}

最低0.47元/天 解锁文章
85

被折叠的 条评论
为什么被折叠?



