這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
Go使用channel和goroutine開發並行程式。goroutine 是 Go並發能力的核心要素。
goroutine 是一個普通的函數,只是需要使用關鍵字 go 作為開頭。
ready("Tea", 2) // 普通函數調用go ready("Tea", 2) // ready() 作為 goroutine 運行
Go routine實踐
func ready(w string, sec int) { time.Sleep(time.Duration(sec) * time.Second) fmt.Println(w,"is ready!")}func main() { go ready("Tea", 2) go ready("Coffee", 1) fmt.Println("I'm waiting") time.Sleep(5 * time.Second)}// 輸出 I'm waiting //立刻Coffee is ready! //1秒後Tea is ready! //2秒回
如果不等待goroutine的執行(例如移除第17行),程式會立刻終止,而任何正在執行的goroutine都會停止。為了修複使用channels機制來和goroutine通訊。可以通過channel發送或接受值。這些值只能是特定的類型:channel 類型。
注意,必須使用 make 建立 channel:
ci := make(chan int) //建立 channel ci 用於發送和接收整數cs := make(chan string) //建立 channel cs 用於字串cf:=make(chan interface{})//channel cf 使用了空介面來滿足各種類型
向 channel 發送或接收資料,是通過類似的操作符完 成的:<−. 具體作用則依賴於操作符的位置:
ci <− 1 // 發送整數 1 到 channelci<−ci // 從 channel ci 接收整數i := <−ci // 從 channel ci 接收整數,並儲存到 i 中
上面的例子使用channel後變為:
var c chan int //定義 c 作為 int 型的 channel。就是說:這個 channel 傳輸整數。注意這個變數是 全域的,這樣 goroutine 可以訪問它;func ready(w string, sec int) { time.Sleep(time.Duration(sec) * time.Second) fmt.Println(w, "is ready!") c <- 1 //發送整數 1 到 channel c;}func main() { c=make(chan int) //初始化c; go ready("Tea", 2) //用關鍵字 go 開始一個 goroutine; go ready("Coffee", 1) fmt.Println("I'm waiting, but not too long") <−c // 等待,直到從 channel 上接收一個值。注意,收到的值被丟棄了; <−c// 兩個 goroutines,接收兩個值。}// 如果不知道啟動了多少個goroutine,可以使用select監聽channel上輸入的資料L: for { select { case <−c: i++ if i>1{ break L } }}// 現在將會一直等待下去。只有當從 channel c 上收到多個響應時才會退出迴圈 L。
雖然 goroutine 是並發執行的,但是它們並不是並行啟動並執行。如果不告訴 Go 額外的 東西,同一時刻只會有一個 goroutine 執行。利用 runtime.GOMAXPROCS(n) 可以設定 goroutine 並存執行的數量。如果不希望修改任何原始碼,同樣可以通過設定環境變數 GOMAXPROCS 為目標值。
當在 Go 中用 ch := make(chan bool) 建立 chennel 時,bool 型的 無緩衝 channel 會 被建立。channel同樣可以指定緩衝大小,ch := make(chan bool, 4),建立了可以儲存 4 個元素的 bool型channel。在這個 channel 中,前 4 個元素可以無阻塞的寫入。當寫入第 5 元素時,代碼 將會阻塞,直 到其他 goroutine 從 channel 中讀取一些元素,騰出空間。
當 channel 被關閉後,讀取端需要知道這個事情。
x, ok = <−ch
當 ok 被賦值為 true 意味著 channel 尚未被關閉,同時 可以讀取資料。否則 ok 被賦值為 false。在這個情況下表示 channel 被關閉。