標籤:

Golang 學習筆記三

goroutine

A goroutine is a light weight thread managed by the Go runtime.

go f(x, y, z)

`f, x, y, z` 的計算會發生在當前 goroutine,但執行在另一個新的 goroutine

goroutine 運行在同一個地址空間,所以訪問共享內存時需要同步

channel

Go 哲學不要使用共享內存通信,而是通過 channel 通信來達到共享內存的目的

channel 是用於 goroutine 之間的通信

通道是一個通信管道,可以通過通道操作符 `<-` 來接收,發送消息(PS: 估計類似與進程管道進行通信)

表現同時也像隊列,先進先出。普通 channel 可以用來做同步控制(synchronization),因為 channel 的一方必須等另一方準備完成才能進行讀寫,比如:

Sender 把一個數據放進 channel,Reader 還未進行讀,此時 Sender 再次把數據放進 channel 就會阻塞 Sender,知道 Reader 把數據從 channel 讀取出來

一個 goroutine 可以寫和讀 channel,但是不能夠讀自己寫的數據,讀自己寫的數據將會發生阻塞,如果所有 goroutine 都 asleep 那麼 go runtime 認為出現了死鎖

ch <- v // 發送 v 到 channel chv := <-ch // 從 channel ch 接收一個值,並且賦予 v

數據流動方向就是箭頭方向,`<-`

創建 channel

ch := make(chan int)

默認情況下,直到對方準備好,才開始發送和接收消息。這提供了 goroutine 之間的同步機制,而不是採用特殊的鎖或條件變數

buffered channel

channel 可以是有緩存的,提高緩存的長度用來初始化 channel

ch := make(chan int, 2)

向滿的 buffered channel 中輸入數據,或者是向空 buffered channel 中讀取數據,會發生錯誤

Range and Close

發送者可以 `close` 關閉 channel,表明沒有再多的元素被發送;

接受者可以測試一個 channel 是否已經關閉 `v, ok := <- ch`

只有發送者才能夠關閉 channel,向已經關閉了的 channel 發送數據會引發 `panic`

`ok == false` 如果 channel 中沒有更多元素,channel 已經被關閉

使用 for 循環讀取 channel 中的數據,直到 channel 被關閉

for i := range ch

不像文件,關閉 channel 並不是必須的。只有當需要通知接受者沒有更多的元素時,才需要主動關閉 channel,例如通知接受者停止 `for i := range ch` 循環

讀取 buffered channel 目前元素個數 `length` 和可以容納的最多元素個數 `capability`

len(ch)cap(ch)

從 channel 中不斷發送和讀取 fibonacci 數列

func fibonacci(n int, ch chan int) {x, y := 0, 1for i := 0; i < n; i++ { ch <- yx, y = y, x + y }close(ch)}func main() {ch := make(chan int, 10)go fibonacci(cap(ch), ch)// 不斷地讀取元素,直到 channel closedfor i := range ch { fmt.Println(i) }}

select

select 從多個 channel 中隨機選取一個可讀或者可寫的 channel,執行該 case。

func fibonacci(c, quit chan int) {x, y := 0, 1for {select {case c <- y:x, y = y, x+y// 從 quit 通道中讀取元素,但是沒有發生賦值case <-quit: fmt.Println("quit")return } }}func main() {c := make(chan int)quit := make(chan int)go func() {// 從 c 中讀取 10 個元素,然後向 quit 中發送信號,讓程序退出for i := 0; i < 10; i++ { fmt.Println(<-c) } quit <- 0 }()fibonacci(c, quit)}

time.After

用於控制超時 select

select {case v := <-ch:doSomething()// time.After 可以保證一定時間後 channel 即可通信case <-time.After(1 * time.Second):timeout()}

sync.Mutex

sync.Mutex 用於同步,比如上鎖等操作

mux.Lock() // 上鎖defer mux.Unlock() // 解鎖

goroutine 不是 thread,每一個 goroutine 都擁有一個自己的調用棧。goroutine 開銷很低,可以同時開啟上千個 goroutine。

有可能一個 thread 中有上千個 goroutine。goroutine 多路動態復用 thread,也就是說真正執行計算的還是 thread,但是一個 thread 可能利用非同步等技術來 concurrent 並發多個 goroutine 執行,並且減少切換 thread 上下文的成本。


推薦閱讀:

TAG:Go語言 | 筆記 |