這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
並發concurrency
- 很多人都是衝著Go大肆宣揚的高並發而忍不住躍躍欲試,但其實從源碼解析來看,goroutine只是由官方實現的超級“線程池”而已。不過話說回來,每個執行個體4-5KB的棧記憶體佔用和由於實現機制而大幅減少的建立和銷毀開銷,是製造Go號稱的高並發的根本原因。另外goroutine的簡單易用,也在語言層面上給予了開發人員的巨大的便利。
並發不是並行 Concurrency Is Not Parallelism
- 並發主要由切換時間片來實現“同時”運行,在並行則是直接利用多核實現多線程的運行,但Go可以設定使用核心數,以發揮多核電腦的能力
- Goroutine 奉行通過通訊來共用記憶體,而不是共用記憶體來通訊。
Channel
- Channel 是 goroutine 溝通的橋樑,大都是阻塞同步的
- 通過 make 建立,close 關閉
- Channel 是參考型別
- 可以使用 for range 來迭代不斷操作 channel
- 可以設定單向或雙向通道
- 可以設定緩衝大小,在未被填滿前不會發生阻塞
通過 make 建立,close 關閉
package mainimport ( "fmt")func main() { c := make(chan bool) //聲明一個channel go func() { fmt.Println("GOOD---") c <- true //存入這個channel }() <-c //取出這個channel //當這個main函數執行的時候,遇到gorouting時會直接執行到<-c,此時這個程式會阻塞,一直等到有true存入這個channel(c<-true),此時(<-c)才能讀出來,main函數完成}
可以使用 for range 來迭代不斷操作 channel
package mainimport ( "fmt")func main() { c := make(chan bool) go func() { fmt.Println("GOOD---") c <- true close(c) //關閉這個channel,迭代操作會終止 }() for v := range c { fmt.Println(v) }}
可以設定緩衝大小,在未被填滿前是非同步,不會發生阻塞
package mainimport ( "fmt" "runtime")func main() { runtime.GOMAXPROCS(runtime.NumCPU()) //1.8預設使用多核CPU c := make(chan bool, 10) for i := 0; i < 10; i++ { go Go(c, i) } for i := 0; i < 10; i++ { <-c }}func Go(c chan bool, index int) { a := 1 for i := 0; i < 1000000; i++ { a += i } fmt.Println(index, a) c <- true}/*如果設定了緩衝大小,大小在未被填滿之前,它是非同步,不會發生阻塞如果這個channel沒有緩衝的話,要注意取出的操作要在寫入的操作的前面*/
package mainimport ( "fmt" "runtime" "sync")func main() { runtime.GOMAXPROCS(runtime.NumCPU()) //1.8預設使用多核CPU wg := sync.WaitGroup{} wg.Add(10) for i := 0; i < 10; i++ { go Go(&wg, i) } wg.Wait() //通過同步包來實現多個gorouting同步內容}func Go(wg *sync.WaitGroup, index int) { a := 1 for i := 0; i < 1000000; i++ { a += i } fmt.Println(index, a) wg.Done()}/*如果設定了緩衝大小,大小在未被填滿之前,它是非同步,不會發生阻塞如果這個channel沒有緩衝的話,要注意取出的操作要在寫入的操作的前面*/
Select
- 可處理一個或多個 channel 的發送與接收
- 同時有多個可用的 channel時按隨機順序處理
- 可用空的 select 來阻塞 main 函數
- 可設定逾時
package mainimport ( "fmt")func main() { c1, c2 := make(chan int), make(chan string) o := make(chan bool) go func() { for { select { case v, ok := <-c1: if !ok { o <- true break } fmt.Println("c1", v) case v, ok := <-c2: if !ok { o <- true break } fmt.Println("c2", v) } } }() c1 <- 1 c2 <- "hi" c1 <- 3 c2 <- "hello" close(c1) close(c2) <-o}
select設定逾時
package mainimport ( "fmt" "time")func main() { c := make(chan bool) select { case v := <-c: fmt.Println(v) case <-time.After(3 * time.Second): //返回的是一個time類型的chan fmt.Println("TimeOut") }}