Go語言管道

Channel概念

Channel 是Go中的一個核心類型,你能夠把它當作一個管道Channel是引用類型,操做符是箭頭 <- 安全

Channel 是 CSP 模式的具體實現,用於多個 goroutine 通信。其內部實現了同步,確保併發安全。併發

Channel 是線程安全的先進先出,多個goroutine同時訪問,不須要加鎖,channel是有類型的,一個整數的channel只能存放整數。函數

 

Channel定義

第一種,channel聲明spa

聲明int類型的chan線程

var ch chan int

聲明string類型的chancode

var ch chan string

聲明map類型chanblog

var ch chan map[int]string

第二種,使用make定義,無緩衝channel同步

var ch1 chan int = make(chan int)
var ch2 = make(chan int)
ch3 := make(chan int)

第三種,使用make定義,有緩衝channelstring

var ch1 chan int = make(chan int, 10)
var ch2 = make(chan int, 10)
ch3 := make(chan int, 10)

第四種,只讀channel編譯

var ch1 <-chan int
var ch2 <-chan int = make(<-chan int, 10)
var ch3 = make(<-chan int, 10)
ch4 := make(<-chan int, 10)

第五種,只寫channel

var ch1 chan<- int
var ch2 chan<- int = make(chan<- int, 10)
var ch3 = make(chan<- int, 10)
ch4 := make(chan<- int, 10)

Channel特色

無緩衝的與有緩衝channel有着重大差異,那就是一個是同步的 一個是非同步的。

好比

無緩衝chan:ch1:=make(chan int)

有緩衝chan:ch2:=make(chan int,1)

無緩衝: ch1<-1 不單單是向 c1 通道放 1,而是一直要等有別的攜程 <-ch1 接手了這個參數,那麼ch1<-1纔會繼續下去,要否則就一直阻塞着。

有緩衝: ch2<-1 則不會阻塞,由於緩衝大小是1(實際上是緩衝大小爲0),只有當放第二個值的時候,第一個還沒被人拿走,這時候纔會阻塞。

緩衝區是內部屬性,並不是類型構成要素。

普通 channel 能夠隱式轉爲只讀channel或只寫channel。

package main

var ch = make(chan int, 3)
var send chan<- int = ch
var recv <-chan int = ch

func main() {

}

只讀channel或只寫channel不能轉爲普通 channel。

package main

func main() {
    var send chan<- int
    var recv <-chan int

    ch1 := (chan int)(send)
    ch2 := (chan int)(recv)
}

編譯錯誤:

./main.go:7:19: cannot convert send (type chan<- int) to type chan int
./main.go:8:19: cannot convert recv (type <-chan int) to type chan int

Channel操做

使用內置函數 len() 返回未被讀取的緩衝元素數量,使用內置函數 cap() 返回緩衝區大小。

package main

import "fmt"

func main() {
    ch1 := make(chan int)
    ch2 := make(chan int, 3)

    ch2 <- 1

    fmt.Printf("ch1 緩衝元素數量:%v,緩衝區大小:%v\n", len(ch1), cap(ch1))
    fmt.Printf("ch2 緩衝元素數量:%v,緩衝區大小:%v\n", len(ch2), cap(ch2))
}

運行結果:

ch1 緩衝元素數量:0,緩衝區大小:0
ch2 緩衝元素數量:1,緩衝區大小:3

channel 寫入、讀取操做:

package main

import "fmt"

func main() {
    ch := make(chan int, 1)
    // 寫入chan
    ch <- 99

    // 讀取chan
    value, ok := <-ch
    if ok {
        fmt.Printf("讀取chan:%v\n", value)
    }

}

channel 關閉操做

一、使用內置函數 close() 進行關閉 chan。
二、chan關閉以後,for range遍歷chan中已經存在的元素後結束。
三、沒有使用for range的寫法須要使用,val, ok := <- ch進行判斷chan是否關閉。

package main

import "fmt"

func main() {
    ch := make(chan int, 5)

    ch <- 1
    ch <- 2
    ch <- 3

    close(ch)
    for {
        val, ok := <-ch
        if ok == false {
            fmt.Println("chan is closed")
            break
        }
        fmt.Println(val)
    }

注意:向已經關閉的 channel 發送數據會引起 panic 錯誤。

package main

func main() {
    ch := make(chan int, 1)
    close(ch)
    ch <- 100
}

運行錯誤:

panic: send on closed channel
相關文章
相關標籤/搜索