对 channel 进行读、写、关闭操作会怎么样 ?

本文最后更新于:2 个月前

对 channel 进行读、写、关闭操作会怎么样 ?

  • 对 nil 的 channel 进行读和写 都会造成当前 goroutine 永久阻塞(如果当前 goroutine 是 main goroutine,则会让整个程序直接报 fatal error 退出),关闭则会发生 panic(但这里我们不要忘记,还有一种叫做非阻塞(select default )的方式操作 channel,这种模式下,就算对为 nil 的 channel 读写,也不会阻塞的)

  • 对不为 nil,并且未关闭的 channel 操作,读和写都有两种情况:

    1. 读操作:
      成功读取:如果 channel 中有数据,直接从 channel 里面读取,如果此时写等待队列里面有 goroutine,还需要将队列头部 goroutine 数据写入到 channel 中,并唤醒这个 goroutine;如果 channel 没有数据,就尝试从写等待队列中读取数据,并做对应的唤醒操作

    (读操作无法及时完成)阻塞挂起:channel 里面没有数据 并且 写等待队列为空,则当前 goroutine 加入 读 i.等待队列中,并挂起,等待唤醒

    1. 写操作
      成功写入:如果 channel 读等待队列不为空,则取 头部 goroutine,将数据直接复制给这个头部 i.goroutine,并将其唤醒,流程结束;否则就尝试将数据写入到 channel 环形缓冲中

    (写操作无法及时完成)阻塞挂起:通道里面 buf 满了 并且 读等待队列为空,则当前 gorotine 加入写等待队 i.列中,并挂起,等待唤醒

  • 对已经关闭的 channel 进行写和关闭 都会导致 panic,而读取是直到读完 channel 中剩余数据,还想读的话,就会获得零值

  • select 分为两种,包含非阻塞型 select (包含 default 分支的)和阻塞型 select (不包含 default 分支的)

阻塞型:

1
2
3
4
5
6
7
8
9
10
package main

func main(){
ch:=make(chan int)
select {
case <-ch:

case ch<-1:
}
}

非阻塞型:

1
2
3
4
5
6
7
8
9
10
11
12
13
package main

func main(){
ch := make(chan int)
select {
case <-ch:

case ch <- 1:

default:

}
}

关注我获取更新


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!