當被問到為什么用Go語言,一定不得不提的是Go語言的並發程序編寫。在C語言中編寫非常繁瑣復雜的並發程序在Go語言中總是顯得如此便捷。
Go中並發程序依靠的是兩個:goroutine和channel
理解什么是goroutine?
對於初學者,goroutine直接理解成為線程就可以了。當對一個函數調用go,啟動一個goroutine的時候,就相當於起來一個線程,執行這個函數。
實際上,一個goroutine並不相當於一個線程,goroutine的出現正是為了替代原來的線程概念成為最小的調度單位。一旦運行goroutine時,先去當先線程查找,如果線程阻塞了,則被分配到空閑的線程,如果沒有空閑的線程,那么就會新建一個線程。注意的是,當goroutine執行完畢后,線程不會回收推出,而是成為了空閑的線程。
關於goroutine的理解,推薦看這個帖子:http://groups.google.com/group/golang-china/browse_thread/thread/0e9d683ca766ec00
goroutine的使用
使用非常簡單,在函數前增加一個go
f(11)
go f(11) //這個是讓f()函數作為goroutine運行
但是go有一個缺點,主線程要等待一個goroutine結束再處理怎么辦?拿《學習go語言》中的一個例子說明。
這里的第18行為什么要sleep? 這里是為了等上面兩個go ready處理完成。
好了,這里就出來了一個需求:一個goroutine結束后必須要向主線程傳輸數據,告訴主線程這個goroutine已經結束了。
這里就引進了channel的概念
channel的使用
channel的意思用白話可以這么理解:主線程告訴大家你開goroutine可以,但是我在我的主線程開了一個管道,你做完了你要做的事情之后,往管道里面塞個東西告訴我你已經完成了。
上面的例子就可以改為:
從這個程序得到的幾點信息:
1 channel只能使用make來進行創建
基本格式是 c := make(chan int)
int是說明這個管道能傳輸什么類型的數據
2 往channel中插入數據的操作
c <- 1
是不是很形象
3 從channel中輸出數據
<- c
4 為什么需要輸出兩次(4和5兩行?)
因為2和3啟動了兩個goroutine,每個goroutine都往管道輸出一個1,因此主線程要接收兩次才能說明兩個goroutine都結束了
channel的進一步理解:
http://blog.dccmx.com/2011/05/magic-of-channel-in-go/
http://blog.dccmx.com/2012/03/small-problem-about-goroutine/
channel分為兩種:一種是有buffer的,一種是沒有buffer的,默認是沒有buffer的
ci := make(chan int) //無buffer
cj := make(chan int, 0) //無buffer
cs := make(chan int, 100) //有buffer
有緩沖的channel,因此要注意“放”先於“取”
無緩沖的channel,因此要注意“取”先於“放”
http://blog.dccmx.com/2011/05/magic-of-channel-in-go/ 里面的一個例子很好:
同樣要先輸出hello world,使用有緩沖的channel和無緩沖的channel分別是這樣的:
有緩沖的channel:
var a string var c = make(chan int, 10) func f() { a = "hello, world" c <- 0 } func main() { go f() <-c print(a) }
這里有個緩沖,因此放入數據的操作c<- 0先於取數據操作 <-c
無緩沖的channel:
var a string var c = make(chan int) func f() { a = "hello, world" <-c } func main() { go f() c <- 0 print(a) }
由於c是無緩沖的channel,因此必須保證取操作<-c 先於放操作c<- 0
參考文檔:
Go語言中的channel魔法
http://blog.dccmx.com/2011/05/magic-of-channel-in-go/
談點對goroutine的理解
http://comments.gmane.org/gmane.comp.lang.go.china/676
goroutine效果測試
Effective Go