標籤:並發 go channel goroutine
go語言並發編程上
傍晚抽空學習了下go語言的並發編程,從goroutine到channel機制,從開始的稀裡糊塗到現在撥開雲霧見太陽的感覺,學習的過程總是令人亢奮的!當然目前的理解還是不夠透徹的。下篇將舉例來分析下。
goroutine
類似開闢進程、線程做法,go語言所採用的為 goroutine 。用法極其簡單,也就是使用go關鍵字,使用方法有兩種:
下面簡單代碼加深下:
/////////第一種範例程式碼://///////// func sayHello(name string){ fmt.Println("hello"+name) } //主程式入口 func main(){ go sayHello("PMST") } /////////第二種範例程式碼:////////// //主程式入口 func main(){ go func(){ fmt.Println("hello world") }() //別忘記這裡的() }
現在來講下go關鍵字作用,一旦將go放在函數之前,意味分配一個子routine讓這個函數自個玩去(有點自身自滅的感覺),而主routine則繼續該幹嘛幹嘛。打個比方,手頭有一堆資料,需要經過超級複雜,超級耗時的計算才能得出答案。顯然我們的主routine不可能只幹這一件事,它還有其他事情需要處理。因此,我們開闢一個routine讓其自個算去。
那麼問題來了,這麼做確實解決了主routine不被鎖死的問題,又能夠完成了耗時計算,可是計算出答案之後,如何回傳給主routine使用呢?
這也就是下面channel的使用了
channel
goroutine 之間如何進行資料的通訊?如下兩種:
共用記憶體記憶體空間。
Go語言推薦的通訊機制channel。
接下來是我對channel的一些理解:
Goroutine使用channel 接收或者發送值,而這些值只能是特定的類型,由自己指定,比如兩個routine之間相互傳值為int類型,那麼channel類型就是chan int
通過make來建立channel,例如無緩衝ci := make(chan int),指定緩衝cib := make(chan int,2)。很明顯可以看出,區別在於後面的表述,後者表示給這個通道分類了2個緩衝空間,至於區別,下文馬上給出。
channel 通過<- 來接收和發送資料。例如 channel <- value ,顯然就是把值 value 發送到通道 channel 中; value := <- ch ,注意箭頭,表示從通道 channel 讀取資料給 value ,或者可以說從通道channel接收資料賦值給value。順便提及其他的寫法<- channel,顯然也是從通道讀取資料,但是沒有賦值給任何一個變數,因此表示丟棄!
關於channel的阻塞問題,我想有必要著重梳理下。請看下面的總結
首先通道的接收和發送都是阻塞的,除非與之對應的一端已經準備好。通過舉例來說明是最好不過了。
建立一個通道,channel_c := make(chan int),注意是沒有分配緩衝的。
隨後往通道寫入資料,channel_c <- value,由於沒有分配緩衝,因此這裡會被堵塞掉,換句話說就是卡死在這裡,只能等待,等待程式某個地方從該通道讀取資料!(ps:就好比非常短的管子,就往裡塞了一個資料,就要漏出來,因此我一直手”扶著”資料,騰不出手幹下面的事了。只有當接收方來拿資料了才能騰出手來幹別的事。)
2015.04.22 -> 對上面比喻修改。ps:上面比喻的不是很恰當,我想是不是可以這麼認為,channel是連通兩個routine的通道,當寄件者向channel裡發送資料,卻遲遲等不到接收者,但秉著盡職盡責的思想,始終等待在那個位置,即channel_c := make(chan int)這條發送語句處,直到接收者接收了通道資料,才可以進行下一條語句。那麼假如有緩衝就不同了,就好比一個驛站,拿著資料到通道這發送“郵件”,儘管可能沒有接收者,但是我卻可以先暫時放到“驛站”(緩衝)這裡,然後繼續幹自己的活,等下次再向通道發送資料時發現緩衝滿了,就只能耐心等待,除非這時有人來取資料,騰出緩衝空間了,才可以寫入資料。
現在換成從通道讀取資料,v := <- channel_c,分兩種情況:當channel_c通道中有資料時,那肯定不會堵塞,很順利的讀過來;當channel_c通道沒有資料時,那麼自然又堵死了,除非程式其它地方往通道寫入資料了!
最後講講關於分配了緩衝的通道,例如:channel := make(chan int,2)。假如這時候往通道寫入資料channel <- 2,由於分配了緩衝,意味著是我可以直接寫入,不會堵塞了,但這僅當我的緩衝區未滿的情況下才不會堵塞。下面往通道寫入一個channel <- 3,這是沒有問題的。不過緩衝已經填滿了!假如這時候你再寫的話就會堵塞,只有程式某個地方從改通道讀取資料騰出地方了,你才可以寫入!
go學習筆記_Routine和Channel