How channel works
Note of
https://www.youtube.com/watch?v=KBZlN0izeiY&ab_channel=GopherAcademy
by Kavya Joshi.
Channel !!!
goroutine-safe
store data、FIFO
pass data between goroutines
block, unblock goroutine
making channels
https://golang.org/src/runtime/chan.go
- hchan struct contains
buf -> circular queue (with send index & receive index)
sendx
recvx
mutex
sendq // list of sudo g
recvq // list of sudo g
…
ch := make(chan Task, 3)
This comman allocates an hchan on the heap
ch is a pointer to hchan
sends and receives
sender sends
- acquires lock
- put a copy of data into channel buf
- releases lock
no shared memory except hchan between goroutines
what if a sender trys to send data into a full channel?
Sender (G1), Receiver(G2)
Sender G1
G1 creates a sudog(of itself, this contains goroutine pointer and data) and puts it into the sendq.
G1 calls the scheduler to detach(gopark) G1 from the M and set G1 to waiting state.
Then the scheduler pops a runnable G from runq and schedules it to run on the M.
Sender is blockd but not the OS thread.
How to resume?
Receiver
Get an element from channel buf then pops a sudog from sendq.
Enqueue data(in poped sudog) into buf.
Calls into the scheduler to set the waiting sender(G1) to runnable and put it in runq of P(or global queue).
Returns to Receiver
what if a receiver trys to receive data on an empty channel?
Sender (G1), Receiver(G2)
Receiver
G2 puts a sudog into recvq then call gopark to detach from M.
Sender
G1 enqueue data into the buf, and call goready???
No,
G1 writes to memory location of G2 directly
G1 writes to G2’s stack
G2 does not need to access the channel, and fewer memory copy
design considerations
simplicity
queue + lock v.s. lock-free
performance
So threads not blocked
cross-goroutine stack & reads writes
goroutine wake up is lockless
fewer memory copy
others
nbufferd channel: read and write directly to each other’s stack
select: put the current goroutine to sendq and recvq of the channels in cases then call scheduler.