Go的並發沒有它,就像iphone沒有網路一樣
簡介
Golang的並發屬性是該語言的一個大殺器,說到並發就不能不提Channel
,你可以把它看成一個管道,通過它並發核心單元就可以發送或者接收資料進行通訊。這篇文章來深入瞭解一下 channel。
channel 的設計是基於 CSP 模型的。CSP 是 Communicating Sequential Process 的簡稱,中文可以叫做通訊順序進程,是一種並發編程模型,由 Tony Hoare 於 1977 年提出。簡單來說,CSP 模型由並發執行的實體(線程或者進程)所組成,實體之間通過發送訊息進行通訊,這裡發送訊息時使用的就是通道,或者叫 channel。CSP 模型的關鍵是關注 channel,而不關注發送訊息的實體。Go 語言實現了 CSP 部分理論,goroutine 對應 CSP 中並發執行的實體,channel 也就對應著 CSP 中的 channel。
建立Channel
aChan := make(chan int) // 建立無緩衝chanbChan := make(chan int, N) // 建立緩衝為N的chan</pre>
賦值和取值
從以下代碼中看不出它的巨大作用,很正常,那是因為他們兩條語句通常不在一起,例如:協程A發送資料,協程B接收資料。
mchan <- value // 發送值v到Channel ch中value := <-mchan // 從Channel ch中接收資料,並將資料賦值給v
Select
Selsect是擷取Channel中資料的最常用方式。
select 一定程度上可以類比於 linux 中的 IO 多工中的 select。後者相當於提供了對多個 IO 事件的統一管理,而 Golang 中的 select 相當於提供了對多個 channel 的統一管理。當然這隻是 select 在 channel 上的一種使用方法。
func main(){ ch1 := make(chan int, 1) ch2 := make(chan int, 1) select { case e1 := <-ch1: //如果ch1通道成功讀取資料,則執行該case處理語句 fmt.Printf("1th case is selected. e1=%v",e1) case e2 := <-ch2: //如果ch2通道成功讀取資料,則執行該case處理語句 fmt.Printf("2th case is selected. e2=%v",e2) default: //如果上面case都沒有成功,則進入default處理流程 fmt.Println("default!.") }}
for...range
for …… range語句可以處理Channel。
go func() { time.Sleep(1 * time.Hour) }() c := make(chan int) go func() { for i := 0; i < 10; i = i + 1 { c <- i } close(c) }() for i := range c { fmt.Println(i) } fmt.Println("Finished")
timeout
Select很重要的一個應用就是逾時處理。 因為上面提供的demo,select語句就會一直阻塞著。這時候我們可能就需要一個逾時操作,用來處理逾時的情況。下面這個例子我們會在2秒後往channel c1中發送一個資料,但是Select設定為1秒逾時,因此我們會列印出timeout 1,而不是result 1。
c1 := make(chan string, 1) go func() { time.Sleep(time.Second * 2) c1 <- "result 1" }() select { case res := <-c1: fmt.Println(res) case <-time.After(time.Second * 1): fmt.Println("timeout 1") }
close
Go內建的close方法就可以用來關閉channel。但如果channel 已經被關閉,繼續往它發送資料會導致panic: send on closed channel:
close(mChan)
推薦閱讀:
有,總比沒有要好:Go依賴管理工具dep
工欲善其事,必先利其器 (Go開發工具)