Go channel系列:
當未為channel分配內存時,channel就是nil channel,例如var ch1 chan int。nil channel會永遠阻塞對該channel的讀、寫操作。
nil channel會阻塞對該channel的所有讀、寫。所以,可以將某個channel設置為nil,進行強制阻塞,對於select分支來說,就是強制禁用此分支。
以下是一個nil channel的示例:
package main
import (
"fmt"
"math/rand"
"time"
)
// 不斷向channel c中發送[0,10)的隨機數
func send(c chan int) {
for {
c <- rand.Intn(10)
}
}
func add(c chan int) {
sum := 0
// 1秒后,將向t.C通道發送時間點,使其可讀
t := time.NewTimer(1 * time.Second)
for {
// 一秒內,將一直選擇第一個case
// 一秒后,t.C可讀,將選擇第二個case
// c變成nil channel后,兩個case分支都將一直阻塞
select {
case input := <-c:
// 不斷讀取c中的隨機數據進行加總
sum = sum + input
case <-t.C:
c = nil
fmt.Println(sum)
}
}
}
func main() {
c := make(chan int)
go add(c)
go send(c)
// 給3秒時間讓前兩個goroutine有足夠時間運行
time.Sleep(3 * time.Second)
}
上面的示例中,send()向通道c不斷發送10以內的隨機整數,add()則在一秒內不斷讀取通道c中的數據並進行加總。一秒時間到后,t.C通道就會有數據,第二個case分支就會被選中,第二個case會讓第一個case評估的channel變為nil channel,使得第一個case從此永久禁用,因為第二個case沒有多余的數據可讀,它也被永久禁用。總共3秒之后,main goroutine結束,程序結束。
如果不理解NewTimer(d),換成After(d)是一樣的,After(d)和NewTime(d).C是等價的。
func add(c chan int) {
sum := 0
t := time.After(1 * time.Second)
for {
select {
case val := <-c:
sum = sum + val
case <-t:
c = nil
fmt.Println(sum)
}
}
}