這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
Channel是什麼
在Go語言中,Channel即指通道類型。有時也用它來直接指代可以傳遞某種類型的值的通道。
類型標記法
chan T
- 關鍵字chan代表了通道類型的關鍵字,T則代表了該通道類型的元素類型。
- 例如:type IntChan chan int 別名資料型別IntChan代表了元素類型為int的通道類型。我們可以直接聲明一個chan int類型的變數:var IntChan chan int,在被初始化後,變數IntChan就可以被用來傳遞int類型的元素值了。
chan<- T
- <-chan T
值標記法
屬性和基本操作
- 基於通道的通訊是在多個Goroutine之間進行同步的重要手段。而針對通道的操作本身也是同步的。
- 在同一時刻,僅有一個Goroutine能向一個通道發送元素值
- 同時也僅有一個Goroutine能從它那裡接收元素值。
- 通道相當於一個FIFO先進先出的訊息佇列。
- 通道中的元素值都具有原子性。它們是不可被分割的。通道中的每一個元素都只可能被某一個Goroutine接收。已被接收的元素值會立刻被從通道中刪除。
初始化通道
make(chan int, 10)
~ 運算式初始化了一個通道類型的值。傳遞給make函數的第一個參數表明此值的具體類型是元素類型為int的通道類型,而第二個參數則指該值在同一時刻最多可以容納10個元素值。
package mainimport ( "fmt")type Person struct { Name string Age uint8 Address Addr}type Addr struct{ city string district string}func main(){ persionChan := make(chan Person,1) p1 := Person{"Harry",32,Addr{"Shanxi","Xian"}} fmt.Printf("P1 (1): %v\n",p1) persionChan <- p1 p1.Address.district = "shijingshan" fmt.Printf("P2 (2): %v\n",p1) p1_copy := <-persionChan fmt.Printf("p1_copy: %v\n",p1_copy)}
#go test.go 運行結果P1 (1): {Harry 32 {Shanxi Xian}}P2 (2): {Harry 32 {Shanxi shijingshan}}p1_copy: {Harry 32 {Shanxi Xian}}
通道中的元素值絲毫沒有受到外界的影響。這說明了,在發送過程中進行的元素值屬於完全複製。這也保證了我們使用通道傳遞的值的不變性。
關閉通道
close(strChan)
我們應該先明確一點:無論怎麼樣都不應該在接收端關閉通道。因為在那裡我們無法判斷髮送端是否還會向該通道發送元素值。
package mainimport ( "fmt" "time")func main(){ ch := make(chan int, 5) sign := make(chan int, 2) go func() { for i :=0;i<5;i++ { ch <- i time.Sleep(1 * time.Second) } close(ch) fmt.Println("The channel is closed.") sign <- 0 }() go func() { for { e, ok := <-ch fmt.Printf("%d (%v)\n", e,ok) if !ok { break } time.Sleep(2 * time.Second) } fmt.Println("Done.") sign <- 1 }() <- sign <- sign}
運行結果:
0 (true)
1 (true)
2 (true)
The channel is closed.
3 (true)
4 (true)
0 (false)
Done.
運行時系統並沒有在通道ch被關閉之後立即把false作為相應接收操作的第二個結果,而是等到接收端把已在通道中的所有元素值都接收到之後才這樣做。這確保了在發送端關閉通道的安全性。
未完待續
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。