天天看點

Golang協程之了解管道的緩存能力

Golang協程之了解管道的緩存能力

我們之前講過,當使用make建立管道時,第二個參數為零,就證明這個管道是無緩存能力的管道。隻要沒人寫就永遠讀不出來,隻要沒人讀就永遠寫不進去。例如:

ch := make(chan int,0)           

管道的緩沖區能被初始化為指定的緩沖區容量。 如果為零,或者省略了大小,則該通道是無緩沖的。

如果将第二個參數改為8(這裡可以為任意大小),這就說明緩存能力為8,即使不讀,也能寫入8個元素。

package main

import (
    "fmt"
    "time"
)

func main() {
    //The channel's buffer is initialized with the specified buffer capacity.
    //If zero, or the size is omitted, the channel is unbuffered.
    ch := make(chan int,0)

    go func() {
        ch <- 123
        fmt.Println("資料已寫入")
    }()

    go func() {
        time.Sleep(2*time.Second)
        x:= <- ch
        fmt.Println("資料已讀出",x)
    }()

    time.Sleep(5*time.Second)
    fmt.Println("Game Over!")
}
           

這段代碼在運作過程中,由于一條協程在寫入管道緩沖區,另一條協程在讀取管道的緩沖區,但是讀取管道緩沖區的那條協程會sleep 兩秒,是以在前兩秒另一條寫入管道緩沖區的協程也不能寫入。

如果讓寫入管道緩沖區的那條協程sleep兩秒,那麼前兩秒另一條讀取管道緩沖區的協程也不能讀取資料。

如果一個緩沖區大小為3的管道,寫入4個值,那麼第4個值就寫入不了,運作結果是這樣的:

寫入1
寫入2
寫入3           

下面我們來看一看管道内的元素個數及它的緩存能力吧:

package main

import (
    "fmt"
    "time"
)

func main101() {
    ch := make(chan int,3)

    go func() {
        ch <- 1
        fmt.Println("寫入1")
        ch <- 2
        fmt.Println("寫入2")
        ch <- 3
        fmt.Println("寫入3")
        //管道的緩沖區已經存滿,不能再寫入!
        ch <- 4
        fmt.Println("寫入4")
    }()
    time.Sleep(5 * time.Second)
}

func main() {
    ch := make(chan int,3)
    fmt.Println("元素的個數為",len(ch),"緩存能力為",cap(ch));

    ch <- 123
    fmt.Println("元素的個數為",len(ch),"緩存能力為",cap(ch));
    ch <- 123
    fmt.Println("元素的個數為",len(ch),"緩存能力為",cap(ch));
    ch <- 123
    fmt.Println("元素的個數為",len(ch),"緩存能力為",cap(ch));
    
}           

運作結果是

元素的個數為 0 緩存能力為 3
元素的個數為 1 緩存能力為 3
元素的個數為 2 緩存能力為 3
元素的個數為 3 緩存能力為 3
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:
main.main()
    E:/main.go:36 +0x4e5

Process finished with exit code 2           

我們可以看到管道的緩存能力是沒有變化的,但是存入的元素個數是在變化的。

我們可以看到這裡出現了死鎖,這裡主協程永遠無法繼續執行。

我們再來了解一下管道的有關知識。

據了解,管道是建立在堆上面的。使用make函數傳回的是指針,這就是為什麼我們能夠在函數之間傳遞管道,不需要傳遞指向管道的指針。

ch := make(chan int,0)           

使用make建立一個管道隻能傳輸同一類型的資料,建立一個管道時需要指定一個資料類型,不允許通過一個管道傳輸多種類型的資料。