Channel 是Go中的一個核心類型,你能夠把它當作一個管道。Channel是引用類型,操做符是箭頭 <-
。安全
Channel 是 CSP 模式的具體實現,用於多個 goroutine 通信。其內部實現了同步,確保併發安全。併發
Channel 是線程安全的,先進先出,多個goroutine同時訪問,不須要加鎖,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有着重大差異,那就是一個是同步的 一個是非同步的。
好比
無緩衝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
使用內置函數 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