// exp3 用來測試訪問一個已經關閉的且裏面還有值未取出的 chanel 會發生什麼事? // 結果是先取出 chanel 裏面的值,以後返回零值 func exp3(){ sigCh:= make(chan string) ch:=make (chan int,2) ch <- 3 ch <- 4 close(ch) go func (){ for i:=0;i<6;i++ { fmt.Println("b goroutine recieve: " ,<-ch) } sigCh <-"over" }() <-sigCh }
控制檯結果如圖:segmentfault
// exp4 用來測試往一個已經關閉的 chanel 寫入數據會發生什麼事? // 結果是發生 panic :send on closed channel func exp4 (){ sigCh:= make(chan string) ch:=make (chan int,2) ch <- 3 ch <- 4 close(ch) go func (){ ch <- 6 sigCh <-"over" }() <-sigCh }
控制檯結果如圖:數組
// exp5 關閉已經關閉的 chanel 會發生什麼事? // 結果是發生 panic : close of closed channel func exp5 (){ sigCh:= make(chan string) ch:=make (chan int,2) ch <- 3 ch <- 4 close(ch) go func (){ close(ch) sigCh <-"over" }() <-sigCh }
沒有共享內存(除了 hchan 對象)「不經過共享內存來通訊,而是經過通訊來共享內存」,而怎麼通訊呢?其實就是 copies。緩存
goroutine 是一種用戶級線程,由 Go 運行時系統來建立和管理,而不是操做系統。相較於操做系統的線程更加輕量級。一個 OS thread 對應對個 goroutine。這即是 Go 語言的 M:N 調度模型。安全
MGP 模型,其中 P 爲調度所須要的上下文資源,擁有運行隊列。數據結構
當 G1 發送數據給已經滿了的 chanel 時,會經過調用 gopark() 方法呼叫調度器將當前 goroutine(即 G1)設置爲 waiting 狀態。併發
而後斷開 G1 和 M 的聯繫函數
調度下一條可運行的 goroutine 測試
被阻塞的 發送方、接收方 goroutine 分別保存在 hchan 結構體的 sendq 、recvq 字段中。而且是封裝爲一個個 sudog 結構體對象保存的。ui
G1 建立一個 sudog 結構體對象,而後將 sudog 放入 hchan 類型對象中的 sendq 隊列上。spa
接下來,當 G2 取走 chanel 中的數據,chanel 緩存有空餘,G1 再也不阻塞,可是是誰調用調度器將 G1 喚醒的呢?
如上圖,是 G2 ,經過調用 goready(G1) 方法呼叫調度器將 G1 喚醒。因此說「經過通訊來共享內存」
當 chanel 有數據不爲空了,G1 並非:
而是有一種更聰明的辦法,直接寫到等待接受隊列中的 G2
關於無緩存 chanel ,若是接收方先阻塞,則發送方「直接寫入」數據到接受方的棧結構中。
若是發送方先阻塞,則接收方直接從發送方的 sudog 結構中獲取數據。
引用文章出處:
https://speakerdeck.com/kavya...
https://segmentfault.com/a/11...