go語言併發編程上
傍晚抽空學習了下go語言的併發編程,從goroutine到channel機制,從開始的稀裏糊塗到現在撥開雲霧見太陽的感覺,學習的過程總是令人亢奮的!當然目前的理解還是不夠透徹的。下篇將舉例來分析下。
goroutine
類似開闢進程、線程做法,go語言所採用的爲 goroutine 。用法極其簡單,也就是使用go關鍵字,使用方法有兩種:
定義一個函數functionName,要異步調用時使用語句
go functionName
即可。使用匿名函數,用法爲
go func(參數列表){函數執行體}()
,說明最後一個()
作用就是讓該函數執行。
下面簡單代碼加深下:
/////////第一種示例代碼:///////////
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 <- value
這條發送語句處,直到接收者接收了通道數據,纔可以進行下一條語句。那麼假如有緩存就不同了,就好比一個驛站,拿着數據到通道這發送“郵件”,儘管可能沒有接收者,但是我卻可以先暫時放到“驛站”(緩存)這裏,然後繼續幹自己的活,等下次再向通道發送數據時發現緩存滿了,就只能耐心等待,除非這時有人來取數據,騰出緩存空間了,纔可以寫入數據。現在換成從通道讀取數據,
v := <- channel_c
,分兩種情況:當channel_c通道中有數據時,那肯定不會堵塞,很順利的讀過來;當channel_c通道沒有數據時,那麼自然又堵死了,除非程序其它地方往通道寫入數據了!最後講講關於分配了緩存的通道,例如:
channel := make(chan int,2)
。假如這時候往通道寫入數據channel <- 2
,由於分配了緩存,意味着是我可以直接寫入,不會堵塞了,但這僅當我的緩存區未滿的情況下纔不會堵塞。下面往通道寫入一個channel <- 3
,這是沒有問題的。不過緩存已經填滿了!假如這時候你再寫的話就會堵塞,只有程序某個地方從改通道讀取數據騰出地方了,你纔可以寫入!