goroutine只是由官方實現的超級"線程池"而已,每個實例4 5kb的棧記憶體占用和用於實現機制而大幅減少的創建和銷毀開銷。 併發不是並行(多CPU): 併發主要由切換時間片來實現"同時"運行,並行則是直接利用多核實現多線程的運行,但Go可以設置使用核數,以發揮多核電腦的能力。 通過go關鍵字實 ...
goroutine只是由官方實現的超級"線程池"而已,每個實例4-5kb的棧記憶體占用和用於實現機制而大幅減少的創建和銷毀開銷。
併發不是並行(多CPU):
Concurrency Is Not Parallelism
- 併發主要由切換時間片來實現"同時"運行,並行則是直接利用多核實現多線程的運行,但Go可以設置使用核數,以發揮多核電腦的能力。
- 通過go關鍵字實現多線程
package main import ( "fmt" "time" ) func Go() { fmt.Println("1234...") } func main() { go Go() //go關鍵字構成多線程 time.Sleep(2 * time.Second) //主程式睡眠2s }
Goroutine 奉行通過
通信來共用記憶體
,而不是共用記憶體來通信
。- Channel
- Channel是goroutine溝通的橋梁,大都是阻塞同步的
- 通過make創建,close關閉(當程式簡單時,回自動關閉)
package main import ( "fmt" ) func main() { //主程式 c := make(chan bool) //初始化一個chan類型 go func() { //子程式 fmt.Println("123...") //執行主程式 c <- true //通過<-存入bool類型到chan中 }() fmt.Println(1) //程式執行步驟:1st read_chan := <-c //<-c 從chan中讀取bool,程式執行步驟:2nd fmt.Println(read_chan) //程式執行步驟:3rd } /*output 1st 1 2nd 123... 3rd true */
註意以上程式的執行順序(channel無緩存時):先執行讀取操作
c<-c
,因為channel中沒有值,所以程式發生阻塞,此時執行chanel寫操作
,然後再執行讀操作。Channel是引用類型
可以使用
for range
來迭代不斷操作channel
package main import ( "fmt" ) func main() { c := make(chan bool) //初始化一個chan類型 go func() { //go結合匿名函數,構造併發 fmt.Println("123...") //執行主程式 c <- true //通過<-存入bool類型到chan中 close(c) //關閉通道:必須明確在哪個地方關閉 }() for v := range c { //for迴圈chanel } } /*output 123... true */
可以設置單向(讀&寫)或雙向通道--預設是雙向通道
可以設置緩存大小(預設為0,阻塞),在未被填充前不會發生阻塞(非同步),比如緩存20個,可以同時進行20個讀操作或者寫操作,註意
讀的操作先於寫的操作
package main import ( "fmt" ) func main() { //主程式 c := make(chan bool, 1) //初始化一個chan類型,緩存為2 go func() { //子程式 fmt.Println("123...") //執行主程式,執行步驟:2 c <- true //寫操作,執行步驟:2 }() fmt.Println(2) //執行步驟:1 fmt.Println(123, <-c) //讀操作,執行步驟:2 fmt.Println(3) //執行步驟:3 } /*output 1 2 2 123... 2 123 true 3 3 */
設置緩存後,程式為非同步,讀,寫操作同時完成,當讀取channal中無數據時,也不會造成堵塞,因為與此同時,寫操作也將發生。