golang面试题:对已经关闭的的chan进行读写,会怎么样?为什么?

2023-12-27 16:06:30 浏览数 (2)

问题

对已经关闭的的 chan 进行读写,会怎么样?为什么?

怎么答

读已经关闭的 chan 能一直读到东西,但是读到的内容根据通道内关闭前是否有元素而不同。

如果 chan 关闭前,buffer 内有元素还未读 , 会正确读到 chan 内的值,且返回的第二个 bool 值(是否读成功)为 true。

如果 chan 关闭前,buffer 内有元素已经被读完,chan 内无值,接下来所有接收的值都会非阻塞直接成功,返回 channel 元素的零值,但是第二个 bool 值一直为 false。

写已经关闭的 chan 会 panic

举例

1. 写已经关闭的 chan

代码语言:go复制
package main

func main() {
	ch := make(chan int, 3)
	close(ch)
	ch <- 1
}



panic: send on closed channel                               
                                                            
goroutine 1 [running]:                                      
main.main()                                                 
        D:/goproject/src/github.com/leetcode/test.go:6  0x452. 读已经关闭的 chan

进程 已完成,退出代码为 2

2. 读已经关闭的 chan

代码语言:go复制
package main

import "fmt"

func main() {
	fmt.Println("以下是数值chan")
	c1 := make(chan int, 3)
	c1 <- 1
	close(c1)
	num, ok := <-c1
	fmt.Printf("num=%v,ok=%v", num, ok)
	num1, ok1 := <-c1
	fmt.Printf("num1=%v,ok1=%v", num1, ok1)
	num2, ok2 := <-c1
	fmt.Printf("num2=%v,ok2=%v", num2, ok2)

	fmt.Println("以下是字符串的chan")
	c2 := make(chan string, 3)
	c2 <- "abc"
	close(c2)
	str, ok := <-c2
	fmt.Printf("str=%v,ok=%v", str, ok)
	str1, ok1 := <-c2
	fmt.Printf("str1=%v,ok1=%v", str1, ok1)
	str2, ok2 := <-c2
	fmt.Printf("str2=%v,ok2=%v", str2, ok2)

}

num=1,ok=true
num1=0,ok1=false
num2=0,ok2=false

str="abc",ok=true
str1="",ok1=false
str2="",ok2=false

多问一句

1. 为什么写已经关闭的 chan 就会 panic 呢?

代码语言:go复制
//src/runtime/chan.go/chansend
	if c.closed != 0 {
		unlock(&c.lock)
		panic(plainError("send on closed channel"))
	}

当 c.closed != 0 则为通道关闭,此时执行写,源码提示直接 panic,输出的内容就是上面提到的 "send on closed channel"。

0 人点赞