go做爲一種自然支持併發的語言,它的併發操做特別簡單,以下:緩存
package main func hello(word string) { fmt.Println("hello, ", word) } func main() { word := "world" go hello(word) fmt.Println(word) }
直接在須要併發的語句前加上關鍵字go便可,深刻了解一下go關鍵字背後實際上是執行了一個runtime.newproc()方法新生成一個goroutine來執行接下來的語句。那既然是生成了一個子協程,在平常編碼的過程當中,就確定會涉及到如何在主協程和子協程之間進行通訊的問題。通常地,在go的多線程環境中,咱們一般使用go的管道類型channel來實現通訊,當數據在channel中時,同一時刻只有一個協程可以訪問數據,避免了出現競爭的可能,從而保證了併發安全。安全
可是channel默認是一種阻塞類型,若是編碼的時候不注意代碼的順序,常常會致使程序出現死鎖的狀況。以下代碼就華麗麗的遇到了死鎖:多線程
func say(ch chan int) { ch <- 2 } func main() { ch := make(chan int) say(ch) print(<-ch) }
那應該如何實現非阻塞的channel使用:併發
1. 使用go關鍵字,建立一個新的協程,讓管道的push和pop不在同一個協程中執行就能夠避免死鎖。編碼
func main() { ch := make(chan int) go say(ch) print(<-ch) }
2. 使用有緩存的管道channel,初始化時給channel指定buffer大小,在管道內的數據小於等於buffer值時,不會阻塞;超過則阻塞;線程
func main() { ch := make(chan int, 1) say(ch) print(<-ch) }
3. 使用select關鍵字,該關鍵字能夠監控channel管道中的數據流動,有流動就會觸發相應的case,沒有流動select會一直阻塞,相似於switch.code
func main() { ch := make(chan int) ch1 := make(chan int) go say(ch) select { case c := <-ch1: print(c) default: print("no answer") } }