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建立一個管道隻能傳輸同一類型的資料,建立一個管道時需要指定一個資料類型,不允許通過一個管道傳輸多種類型的資料。