简介
通道(channel) 是Go实现CSP并发模型的关键, 鼓励用通信来实现数据共享。 Dont’ communicate by sharing memory, share memory by communicating.
CSP
: Communicating Sequential Process
创建
chan.go
中 hchan的结构
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
}
type waitq struct {
first *sudog
last *sudog
}
makechan
: 这里先做了一些元素大小,队列大小检查。受垃圾回收器的限制,如果包含指针类型,则缓冲槽需单独分配内存,否则可一次性分配,调整buf的指针,最后设置size等属性
func makechan(t *chantype, size int) *hchan {
elem := t.elem
// compiler checks this but be safe.
if elem.size >= 1<<16 { //限制chan的元素大小
throw("makechan: invalid channel element type")
}
mem, overflow := math.MulUintptr(elem.size, uintptr(size)) //检查是否溢出
if overflow || mem > maxAlloc-hchanSize || size < 0 {
panic(plainError("makechan: size out of range"))
}
var c *hchan
switch {
case mem == 0:
// Queue or element size is zero.
c = (*hchan)(mallocgc(hchanSize, nil, true))
// Race detector uses this location for synchronization.
c.buf = c.raceaddr()
case elem.ptrdata == 0:
// Elements do not contain pointers.
// Allocate hchan and buf in one call.
c = (*hchan)(mallocgc(hchanSize+mem, nil, true))
c.buf = add(unsafe.Pointer(c), hchanSize)
default:
// Elements contain pointers.
c = new(hchan)
c.buf = mallocgc(mem, elem, true)
}
收发
这里用sudog用来保存收发队列,其中包含一个元素和g的指针,这里也实现了cache,central那一套缓存体系.
用acquireSudog
获取sudog和releaseSudog
释放sudog, 大致流程也是先从本地p获取,接着再去sched.sudogcache中获取.
type sudog struct {
g *g
elem unsafe.Pointer // data element (may point to stack)
}
type p struct {
sudogcache []*sudog
sudogbuf [128]*sudog
}
type schedt struct {
// Central cache of sudog structs.
sudoglock mutex
sudogcache *sudog
}
发送
在go1