不要經過共享內存來通訊,要經過通訊來共享內存。bash
Go 支持兩種方式的併發模型: communicating sequential processes(CSP) 和 shared memory multithreading,前者是 goroutine 和 channel 併發模型實現的基礎,後者是傳統的共享內存的方式,也就是多線程模型。數據結構
如何理解 CSP ?簡單來講就是經過在不一樣的 goroutine 之間傳遞 value 來維護併發的下不一樣 goroutine 的狀態,可是對變量的使用、修改要限制在單一的 goroutine 中。多線程
在 Go 中能夠併發執行的活動單元稱之爲 goroutine。當一個 Go 程序啓動時,一個執行 main function 的 goroutine 會被建立,稱之爲 main goroutine
。建立新的 goroutine 可使用 go 語句,像這樣: go f(),其中 f
是一個函數。使用 go 語句開啓一個新的 goroutine 以後,go 語句以後的函數調用將在新的 goroutine 中執行,而不會阻塞當前的程序執行。併發
若是說 goroutine 是併發執行的一個 Go program, channel 就是它們之間的鏈接通道,它提供了 goroutine 之間相互通訊的機制。channel 是有類型的,channel 中使用的 type 稱之爲 element type,好比 int 類型的 channel 寫做爲 chan int
。函數
Go 使用 make 內建函數建立 channel。ui
ch := make(chan int)
複製代碼
同 map 同樣,一個 channel 引用着 make 建立的底層數據結構上,當把 channel 當作函數參數傳遞時,其實是拷貝一份 reference,也就是說函數內部和外部引用的是相同的數據結構,因此在函數內部能夠直接修改 channel 的值。同其它 reference type 同樣,channel 的 zero value 是 nil。spa
channel 是可比較的,若是兩個 channel 的類型相同,它們能夠彼此相互比較:線程
ch01 := make(chan int)
ch02 := make(chan int)
if ch01 == ch02 {
fmt.Println("ch01 == ch02")
} else {
fmt.Println("ch01 != ch02") // return
}
複製代碼
兩個不是 nil 的 channel 比較實際上比較的他們的 reference 是否相同,若是他們都引用同一個 channel,則他們相同:code
func main() {
ch01 := make(chan int)
func02(ch01, ch01)
}
func func02(a chan int, b chan int) {
if a == b {
fmt.Println("a == b") // return
}
}
複製代碼
固然 channel 也能夠和 nil 比較,沒有初始化的 channel 就是 nil:cdn
var ch02 chan int
if ch02 == nil {
fmt.Println("ch02 is nil") // return
}
複製代碼
channel 有三種基本的操做 send、receive、close。
channel 支持 send 操做,意思是向 channel 中發送數據,Go 使用 <-
操做符來實現 send:
ch <- x //send
複製代碼
被send的對象是在 <-
在 channel 右側。
channel 還支持 receive 操做,意思是從 channel 中取出數據,Go 也是使用 <-
操做符來實現 receive:
x, ok := <- ch //receive
複製代碼
receive 時 <-
在左側,若是一個執行 receive 時沒有用任何變量來賦值,則該值被拋棄,receive操做能夠得到2個參數,ok能夠用來判斷channel是否關閉,從一個已關閉的channel獲取值會獲得零值,陷入死循環
receive 的這個操做經常被用來作狀態同步:
<- ch
複製代碼
channel 還支持第三種操做 close
,若是 channel 被 close,代表 channel 不會再 send 任何值了,若是還繼續對 channel 執行 receive 操做,當 channel 中的值消耗完畢以後,以後返回的是對應 element type 的 zero value,若是對 channel 執行 send 操做,將會引發 panic:
close(ch)
ch <- x // panic
複製代碼
close 操做經常和 for 語句配合使用,表示一個 channel 再也不產生新的值:
for x := range ch {
fmt.Print(x)
}
複製代碼
close channel 以後,for 循環將結束。