对 channel 进行读、写、关闭操作会怎么样 ?
对 nil 的 channel 进行读和写 都会造成当前 goroutine 永久阻塞(如果当前 goroutine 是 main goroutine,则会让整个程序直接报 fatal error 退出),关闭则会发生 panic(但这里我们不要忘记,还有一种叫做非阻塞(select default )的方式操作 channel,这种模式下,就算对为 nil 的 channel 读写,也不会阻塞的)
对不为 nil,并且未关闭的 channel 操作,读和写都有两种情况:
读操作:
成功读取:如果 channel 中有数据,直接从 channel 里面读取,如果此时写等待队列里面有 goroutine,还需要将队列头部 goroutine 数据写入到 channel 中,并唤醒这个 goroutine;如果 channel 没有数据,就尝试从写等待队列中读取数据,并做对应的唤醒操作(读操作无法及时完成)阻塞挂起:channel 里面没有数据 并且 写等待队列为空,则当前 goroutine 加入 读 i.等待队列中,并挂起,等待唤醒
写操作
成功写入:如果 channel 读等待队列不为空,则取 头部 goroutine,将数据直接复制给这个头部 i.goroutine,并将其唤醒,流程结束;否则就尝试将数据写入到 channel 环形缓冲中(写操作无法及时完成)阻塞挂起:通道里面 buf 满了 并且 读等待队列为空,则当前 gorotine 加入写等待队 i.列中,并挂起,等待唤醒
对已经关闭的 channel 进行写和关闭 都会导致 panic,而读取是直到读完 channel 中剩余数据,还想读的话,就会获得零值
select 分为两种,包含非阻塞型 select (包含 default 分支的)和阻塞型 select (不包含 default 分支的)
阻塞型:
package main
func main(){
ch:=make(chan int)
select {
case <-ch:
case ch<-1:
}
}
非阻塞型:
package main
func main(){
ch := make(chan int)
select {
case <-ch:
case ch <- 1:
default:
}
}
本作品采用《CC 协议》,转载必须注明作者和本文链接