golang中channel的用法
如果說goroutine是Go語言程式的併發體的話,那麼channels則是它們之間的通訊機制。一個
channel是一個通訊機制,它可以讓一個goroutine通過它給另一個goroutine傳送值資訊。
1 建立channel
每個channel都有一個特殊的型別,也就是channels可傳送資料的型別。一個可以傳送int型別資料
的channel一般寫為chan int。使用內建的make函式,如果第二個引數大於0,則表示建立一個帶快取的channel。
ch := make(chan int) // ch has type 'chan int'
ch = make(chan int, 3) // buffered channel with capacity 3
2 channel的傳送和接受
一個傳送語句將一個值從一個goroutine通過channel傳送到另一個執行接收操作的goroutine。傳送和接收兩個操作都使用<-運算子。在傳送語句中,<-運算子分割channel和要傳送的值。在接收語句中,<-運算子寫在channel物件之前。一個不使用接收結果的接收操作也是合法的。
ch <- x
// a send statement
x = <-ch // a receive expression in an assignment statement
<-ch
// a receive statement; result is discarded
3 channel的close
Channel還支援close操作,用於關閉channel,隨後對基於該channel的任何傳送操作都將導致panic異常。對一個已經被close過的channel進行接收操作依然可以接受到之前已經成功傳送的資料,如果channel中已經沒有資料的話將產生一個零值的資料。使用內建的close函式就可以關閉一個channel:
close(ch)
4 不帶快取的Channels
一個基於無快取Channels的傳送操作將導致傳送者goroutine阻塞,直到另一個goroutine在相同的Channels上執行接收操作,當傳送的值通過Channels成功傳輸之後,兩個goroutine可以繼續執行後面的語句。反之,如果接收操作先發生,那麼接收者goroutine也將阻塞,直到有另一個goroutine在相同的Channels上執行傳送操作。
基於無快取Channels的傳送和接收操作將導致兩個goroutine做一次同步操作。因為這個原因,無快取Channels有時候也被稱為同步Channels。
5 串聯的Channels
Channels也可以用於將多個goroutine連線在一起,一個Channel的輸出作為下一個Channel的輸入。這種串聯的Channels就是所謂的管道(pipeline)。
func main() {
naturals := make(chan int)
squares := make(chan int)
// Counter
go func() {
for x := 0; x < 100; x++ {
naturals <- x
}
close(naturals)
}()
// Squarer
go func() {
for x := range naturals {
squares <- x * x
}
close(squares)
}()
// Printer (in main goroutine)
for x := range squares {
fmt.Println(x)
}
}
當一個被關閉的channel中已經傳送的資料都被成功接收後,後續的接收操作將不再阻塞,它們會立即返回一個零值。
Go語言的range迴圈可直接在channels上面迭代。使用range迴圈依次從channel接收資料,當channel被關閉並且沒有值可接收時跳出迴圈。
6 單方向的Channels
為了防止被濫用,Go語言的型別系統提供了單方向的channel型別,分別用於只傳送或只接收的channel。型別<-chan int表示一個只接收int的channel, chan<- int表示一個只傳送int的channel,(箭頭<-和關鍵字chan的相對位置表明了channel的方向。),這種限制將在編譯期檢測。
func counter(out chan<- int) {
for x := 0; x < 100; x++ {
out <- x
}
close(out)
}
func squarer(out chan<- int, in <-chan int) {
for v := range in {
out <- v * v
}
close(out)
}
func printer(in <-chan int) {
for v := range in {
fmt.Println(v)
}
}
func main() {
naturals := make(chan int)
squares := make(chan int)
go counter(naturals)
go squarer(squares, naturals)
printer(squares)
}
7 帶快取的Channels
帶快取的Channel內部持有一個元素佇列。佇列的最大容量是在呼叫make函式建立channel時通過第二個引數指定的。
向快取Channel的傳送操作就是向內部快取佇列的尾部插入元素,接收操作則是從佇列的頭部刪除元素。如果內部快取佇列是滿的,那麼傳送操作將阻塞直到因另一個goroutine執行接收操作而釋放了新的佇列空間。相反,如果channel是空的,接收操作將阻塞直到有另一個goroutine執行傳送操作而向佇列插入元素。
相關文章
- Golang | 簡介channel常見用法,完成goroutin通訊Golang
- Golang 的 Channel 控制Golang
- Golang 的 Channel 行為Golang
- golang 中fmt用法Golang
- 淺談Golang中select的用法Golang
- Golang Channel 高併發的初始Golang
- 【go】golang中鎖的用法-互斥鎖Golang
- golang開發:channel使用Golang
- Golang通道Channel詳解Golang
- golang-channel詳解Golang
- 轉載golang中net/http包用法GolangHTTP
- 《用好 Channel,用好 Golang》系列之 StreamGolang
- Golang —— goroutine(協程)和channel(管道)Golang
- golang 中 channel 的詳細使用、使用注意事項及死鎖分析Golang
- 如何把 golang 的 Channel 玩出 async 和 await 的 feelGolangAI
- golang遍歷channel時return問題Golang
- channel的單向用法與select,range簡單使用
- Golang channel底層是如何實現的?(深度好文)Golang
- Go基礎系列:雙層channel用法示例Go
- Golang語言之管道channel快速入門篇Golang
- Golang 併發程式設計(channel實現)Golang程式設計
- 「Golang成長之路」併發之Channel下Golang
- 「Golang成長之路」併發之Channel上Golang
- Golang併發程式設計——goroutine、channel、syncGolang程式設計
- 如何用 Golang 的 channel 實現訊息的批量處理Golang
- 如何用 Golang 的 channel 實現訊息的批次處理Golang
- golang flag簡單用法Golang
- Golang筆記--strconv包的基本用法Golang筆記
- 一招教你無阻塞讀寫 Golang channelGolang
- Golang學習筆記(十九):Channel初步接觸Golang筆記
- 「Golang成長之路」併發之channel篇2Golang
- 玩轉Golang的channel,二百行程式碼實現PubSub模式Golang行程模式
- golang package time 用法詳解GolangPackage
- 如何把 Golang 的 channel 用的如 Node.js 的 stream 一樣絲滑GolangNode.js
- Go 中的 channel 怎麼實現的?Go
- 總結了才知道,原來channel有這麼多用法!
- NIO中SelectionKey和Channel、Selector的關係
- netty系列之:netty中的Channel詳解Netty