1. 程式人生 > >Go基礎系列:nil channel用法示例

Go基礎系列:nil 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)
        }
    }
}