Golang中关于Channel读写的一些细节
我们知道,对于一个已经关闭的channle来说,如果channel内部还有值的话,可以继续执行读操作,读出channel里的元素,但是不能执行写操作;
相反,如果关闭后,channel里已经没有元素可读的情况,再执行读操作的话会读出channel的零值,同样,也不能执行写操作。
首先,先让我们通过代码的形式来验证上述的结论:
package main
import "fmt"
func main() {
chan1 := make(chan int, 4)
chan1 <- 1
chan1 <- 2
chan1 <- 3
chan1 <- 4
for i := 0; i < 6; i++ {
fmt.Println(<-chan1)
if i == 3 {
close(chan1)
fmt.Println("i==3时:执行了关闭channel的操作")
}
}
}
下面通过源码来看一下channel,channel关闭后,执行写操作,直接返回panic的信息
if c.closed != 0 {
unlock(&c.lock)
panic(plainError("send on closed channel"))
}
同样的,通道已经关闭,且没有值的情况下,如果接受值的地址不为空,那么接受值将会接受一个该类型的零值,如果还有数据,则继续执行读操作,读channel的数据。
if c.closed != 0 {
if c.qcount == 0 {
if raceenabled {
raceacquire(c.raceaddr())
}
unlock(&c.lock)
if ep != nil {
typedmemclr(c.elemtype, ep)
}
return true, false
}
// The channel has been closed, but the channel's buffer have data.
} else {
// Just found waiting sender with not closed.
if sg := c.sendq.dequeue(); sg != nil {
// Found a waiting sender. If buffer is size 0, receive value
// directly from sender. Otherwise, receive from head of queue
// and add sender's value to the tail of the queue (both map to
// the same buffer slot because the queue is full).
recv(c, sg, ep, func() { unlock(&c.lock) }, 3)
return true, true
}
}