這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
轉載:http://c2pblog.sinaapp.com/archives/450
當今硬體發展迅速,CPU早就變成多核心了,如何處理並發編程以適應多核CPU是每一種現代程式設計語言做重視的點。golang自出生起就宣揚著並發編程,原生的goroutines和channel 很簡潔的支援了複雜的並行操作。
http://blog.csdn.net/gdutliuyun827/article/details/25145535
這篇文章細緻分析了Go語言的特色,在此對原作者表示感謝。
下面邊上代碼邊分析實現過程。
func showNum() { fori := 0; i <30; i++ { fmt.Println(i) atm := time.Duration(rand.Intn(250))//延遲處理 time.Sleep(time.Millisecond * atm) }} |
這是一個簡單的函數,列印出0到29,為了能夠看得比較清楚,我做了相關的延遲處理。
如果在主函數中直接去調用這個函數,那麼就只能列印一次,這就是非並行化的處理。那麼怎麼變成並行化呢?很簡單,調用的時候在前面加上go就好了。
go showNum()
就像這樣。既然是並行,我們就同時調用10次這個函數做一個實驗
fori := 0; i <10; i++ { go showNum() } |
結果你去啟動並執行時候發現什麼東西都跑不出來。
不是沒有跑出來,太快了,看不到,並且每一次go showNum 的結果都被丟棄了。那麼怎麼才能看到結果呢?得想一個辦法讓main停住,那麼就寫這麼一句:
vat in stringfmt.Scanln(&in) |
用標準輸入給main隨便輸入一個值。加上這句話以後你去運行就會發現有數字在列印,並且和java 中thread類似,每一次列印都是隨機的,無法確定的。這個就是最簡單的goroutines了。
簡單來說,任何一個函數如果要做平行處理,那麼就可以再調用這個函數的時候前面加上關鍵詞go 即可。
要講的第二個點就是channel,這個是用來實現goroutine之間通訊的,就是說兩個goroutine之間交換一些資訊<當然主要是相關變數>。定義一個channel的方法是向下面這樣:
var c1 chan string = make(chan string)var c2 = make(chan string)c3 :=make(chan string) |
都是可以的。你要注意的是每一個channel必須有一種類型,並且這個類型是不能隨便混合使用的。golang中有用很形象的方式來表示資訊的傳遞:這就是<-這個東西,
input <-"lkn" //input 是一個chan string ,可以接受一個stringdata<-input //input是一個chan string ,用來傳出一個string |
一般的chan是可以雙向傳遞的,而你如果定義某一個chan只能單向傳遞的話,可以寫成這樣:var c2 = make(chan<- string)或者var c2 = make(<-chan string)。前一個表示只能傳入,後一個表示只能傳出。現在我們用一個簡單的列印素數的例子,結合goroutine和channel。
//素數生產者func prime_generate() chanint {ch := make(chanint)go func() {fori := 2; ; i++ {ch <- i}}()returnch}//素數篩選器func prime_filter(in chanint, primeint) chanint {out := make(chanint)go func() {for{ifi := <-in; i%prime != 0{out <- i}}}()returnout}//素數消費者func prime_sieve() chanint {out := make(chanint)go func() {ch := prime_generate()for{prime := <-chout <- primech = prime_filter(ch, prime)}}()returnout} |
這樣就是可以了,主函數裡面要這樣一直讀100次
primes := prime_sieve() fori := 0; i <100; i++ { fmt.Println(time.Now(), <-primes)
|