Golang中关于Channel读写的一些细节

发布时间 2023-06-06 17:24:08作者: 99号的格调

我们知道,对于一个已经关闭的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
		}
	}