go之通道類型

1.基本知識

通道類型的值本身就是併發安全的,go語言自帶的唯一一個可以滿足併發安全的類型。通道相當於一個先進先出的隊列,發送和接收使用操作符 <-

2.初始化

make(chan type,int)

type: int, string....
int: 可選。通道的容量。0表示不帶緩衝的通道,1表示帶緩衝的通道。

1.初始化容量爲3的雙向通道

package main

import "fmt"

func main() {
    ch1 := make(chan int, 3)
    ch1 <- 2
    ch1 <- 1
    ch1 <- 3
    elem1 := <-ch1
    fmt.Printf("The first element received from channel ch1: %v\n",
        elem1)
}

2.初始化只讀管道

ch1:=make(chan<- int, 1)

example:
func getIntChan() <-chan int {
    num := 5
    ch := make(chan int, num)
    for i := 0; i < num; i++ {
        ch <- i
    }
    close(ch)
    return ch
}

3.初始化只寫管道

ch1:=make(<-chan int, 1)

example:
func SendInt(ch chan<- int) {
    ch <- rand.Intn(1000)
}

3.注意

a.對同一個通道來說,同一時間發送和接收拾互斥的。
b.元素進入通道是複製的副本。
c.緩衝通道滿了以後會阻塞通道。非緩衝通道一開始就會被阻塞,直到有配對的接收操作,纔開始傳輸數據,將數據直接複製到緩衝通道,在複製給接收方。
d.如果通道爲nil,直接發生永久堵塞。
e.確保由發送方關閉通道。如果接收方關閉通道,再次向發送方發送會引發panic。

4.遍歷chan

這種方法有一定的侷限性,如果intChan2 沒有元素或者爲nil,那麼就會在這一行阻塞。

func getIntChan() <-chan int {
    num := 5
    ch := make(chan int, num)
    for i := 0; i < num; i++ {
        ch <- i
    }
    close(ch)
    return ch
}
intChan2 := getIntChan()
for elem := range intChan2 {
    fmt.Printf("The element in intChan2: %v\n", elem)
}

5.select語句

chan專用。類似於 switch,不過select中首先會對所有case求值,然後纔開始選擇,並不是順序求值選擇。如果case 語句阻塞,也代表求值失敗,知道有條件滿足爲止。如果有多個case條件滿足,則用僞隨機算法隨機選擇一個分支執行。若所有分支都未被選中,則默認分支執行。

example1:
// 準備好幾個通道。
intChannels := [3]chan int{
    make(chan int, 1),
    make(chan int, 1),
    make(chan int, 1),
}
// 隨機選擇一個通道,並向它發送元素值。
index := rand.Intn(3)
fmt.Printf("The index: %d\n", index)
intChannels[index] <- index
// 哪一個通道中有可取的元素值,哪個對應的分支就會被執行。
select {
case <-intChannels[0]:
    fmt.Println("The first candidate case is selected.")
case <-intChannels[1]:
    fmt.Println("The second candidate case is selected.")
case elem := <-intChannels[2]:
    fmt.Printf("The third candidate case is selected, the element is %d.\n", elem)
default:
    fmt.Println("No candidate case is selected!")
}

example2:
intChan := make(chan int, 1)
// 一秒後關閉通道。
time.AfterFunc(time.Second, func() {
    close(intChan)
})
select {
case _, ok := <-intChan:
    if !ok {
        fmt.Println("The candidate case is closed.")
        break
    }
    fmt.Println("The candidate case is selected.")
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章